-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature UPDATE js src #5
Changes from 6 commits
d4fbeef
591a2ec
1679685
f1526bd
92be216
0059bb9
36c754e
438ff64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,24 @@ | ||
import React from 'react'; | ||
import { PropTypes as RPT } from 'prop-types'; | ||
|
||
import * as shortid from 'shortid'; | ||
|
||
export default class Script extends React.Component { | ||
|
||
static propTypes = { | ||
onCreate: RPT.func, | ||
onError: RPT.func.isRequired, | ||
onLoad: RPT.func.isRequired, | ||
onUnload: RPT.func.isRequired, | ||
url: RPT.string.isRequired, | ||
}; | ||
|
||
static defaultProps = { | ||
onCreate: () => {}, | ||
onError: () => {}, | ||
onLoad: () => {}, | ||
} | ||
onCreate: () => null, | ||
onError: () => null, | ||
onLoad: () => null, | ||
onUnload: () => null, | ||
}; | ||
|
||
// A dictionary mapping script URLs to a dictionary mapping | ||
// component key to component for all components that are waiting | ||
|
@@ -36,53 +40,99 @@ export default class Script extends React.Component { | |
constructor(props) { | ||
super(props); | ||
this.scriptLoaderId = `id${this.constructor.idCount++}`; // eslint-disable-line space-unary-ops, no-plusplus | ||
this.pkID = `script-${shortid.generate()}`; | ||
this.unmount = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make this a separate function in the component instead of creating it in constructor |
||
const { url, onUnload } = this.props; | ||
const observers = this.constructor.scriptObservers[url]; | ||
const loaded = this.constructor.loadedScripts[url]; | ||
const errored = this.constructor.erroredScripts[url]; | ||
|
||
// If the component is waiting for the script to load, remove the | ||
// component from the script's observers before unmounting the component. | ||
if (observers) { | ||
delete observers[this.scriptLoaderId]; | ||
// delete (this.constructor.scriptObservers)[url]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think It must not be commented, but your latest test fails if I uncomment this line There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. Feel free to fix the tests necessary |
||
} | ||
|
||
// If this script has been previously loaded | ||
if (loaded) { | ||
delete (this.constructor.loadedScripts)[url]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for the parentheses |
||
const s = document.querySelector(`[data-pkID="${this.pkID}"]`); | ||
s.parentNode.removeChild(s); | ||
onUnload(); | ||
} | ||
|
||
// If this script has been previously errored | ||
if (errored) { | ||
delete (this.constructor.erroredScripts)[url]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for the parentheses |
||
} | ||
}; | ||
this.generate = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make this a separate function in the component instead of creating it in constructor |
||
const { onError, onLoad, url } = this.props; | ||
if (this.constructor.loadedScripts[url]) { | ||
onLoad(); | ||
return; | ||
} | ||
|
||
if (this.constructor.erroredScripts[url]) { | ||
onError(); | ||
return; | ||
} | ||
|
||
// If the script is loading, add the component to the script's observers | ||
// and return. Otherwise, initialize the script's observers with the component | ||
// and start loading the script. | ||
if (this.constructor.scriptObservers[url]) { | ||
this.constructor.scriptObservers[url][this.scriptLoaderId] = this.props; | ||
return; | ||
} | ||
|
||
this.constructor.scriptObservers[url] = { [this.scriptLoaderId]: this.props }; | ||
|
||
this.createScript(); | ||
}; | ||
} | ||
|
||
componentDidMount() { | ||
const { onError, onLoad, url } = this.props; | ||
|
||
if (this.constructor.loadedScripts[url]) { | ||
onLoad(); | ||
return; | ||
} | ||
|
||
if (this.constructor.erroredScripts[url]) { | ||
onError(); | ||
return; | ||
} | ||
this.generate(); | ||
} | ||
|
||
// If the script is loading, add the component to the script's observers | ||
// and return. Otherwise, initialize the script's observers with the component | ||
// and start loading the script. | ||
if (this.constructor.scriptObservers[url]) { | ||
this.constructor.scriptObservers[url][this.scriptLoaderId] = this.props; | ||
return; | ||
} | ||
shouldComponentUpdate(nextProps) { | ||
let r = false; | ||
Object.keys(this.props).forEach((k) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be easily rewritten using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can even use shouldComponentUpdate(nextProps) {
return Object.keys(this.props).some(k => this.props[k] !== nextProps[k]
&& !(typeof this.props[k] === 'function' && typeof nextProps[k] === 'function'))
} |
||
if (r) return; | ||
if ( | ||
this.props[k] !== nextProps[k] && | ||
!(typeof this.props[k] === 'function' && typeof nextProps[k] === 'function') | ||
) { | ||
r = true; | ||
} | ||
}); | ||
return r; | ||
} | ||
|
||
this.constructor.scriptObservers[url] = { [this.scriptLoaderId]: this.props }; | ||
componentWillUpdate() { | ||
this.unmount(); | ||
} | ||
|
||
this.createScript(); | ||
componentDidUpdate() { | ||
this.generate(); | ||
} | ||
|
||
componentWillUnmount() { | ||
const { url } = this.props; | ||
const observers = this.constructor.scriptObservers[url]; | ||
|
||
// If the component is waiting for the script to load, remove the | ||
// component from the script's observers before unmounting the component. | ||
if (observers) { | ||
delete observers[this.scriptLoaderId]; | ||
} | ||
this.unmount(); | ||
} | ||
|
||
createScript() { | ||
const { onCreate, url } = this.props; | ||
const { pkID } = this; | ||
const script = document.createElement('script'); | ||
|
||
onCreate(); | ||
|
||
script.src = url; | ||
script.async = 1; | ||
script.setAttribute('data-pkID', pkID); | ||
|
||
const callObserverFuncAndRemoveObserver = (shouldRemoveObserver) => { | ||
const observers = this.constructor.scriptObservers[url]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary for a module? Webpack takes care of this for production builds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok