Remove usages of async-unsafe lifecycle methods#919
Remove usages of async-unsafe lifecycle methods#919timdorr merged 9 commits intoreduxjs:masterfrom JetBrains:strict-mode
Conversation
test/components/connect.spec.js
Outdated
| @connect(null) | ||
| class Parent extends React.Component { | ||
| componentWillMount() { | ||
| UNSAFE_componentWillMount() { |
There was a problem hiding this comment.
When I tried to change it to componentDidMount it broke the test. Maybe it should be changed to constructor, I'm not sure
There was a problem hiding this comment.
What error did you get with cDM? The cWM function is not consequential here anyways; this is testing for unmount cleanups. So, I'd be fine with removing it and putting a dispatch outside of the ReactDOM.render.
src/components/connectAdvanced.js
Outdated
| } | ||
|
|
||
| shouldComponentUpdate() { | ||
| shouldComponentUpdate(nextProps) { |
There was a problem hiding this comment.
This feels like a hack with bad side effects. Can we use getSnapshotBeforeUpdate instead?
There was a problem hiding this comment.
Will try that. Is it called before sCU?
There was a problem hiding this comment.
Looks like it's not: https://reactjs.org/docs/react-component.html#updating
I can try to move selector from field on instance to field on state, then it will be available in static getDerivedStateFromProps
src/components/connectAdvanced.js
Outdated
| const selector = this.selector | ||
|
|
||
| // Handle forceUpdate | ||
| if (!selector.shouldComponentUpdate) selector.run(this.props) |
There was a problem hiding this comment.
Shouldn't this be handled by sCU above?
There was a problem hiding this comment.
sCU doesn't run when forceUpdating
|
Btw let us know when you'll need a final review for whether it's async-safe. |
|
@gaearon I think it's ready for review |
test/components/connect.spec.js
Outdated
| @connect(null, mapDispatchFactory, mergeParentDispatch) | ||
| class Passthrough extends Component { | ||
| componentWillUpdate() { | ||
| componentDIdUpdate() { |
There was a problem hiding this comment.
Will fix & add test
package.json
Outdated
| "loose-envify": "^1.1.0", | ||
| "prop-types": "^15.6.1" | ||
| "prop-types": "^15.6.1", | ||
| "react-lifecycles-compat": "^1.1.4" |
There was a problem hiding this comment.
Why do you need the polyfill when you changed all the deprecated functions?
There was a problem hiding this comment.
He's using getDerivedStateFromProps.
There was a problem hiding this comment.
I am using that too without a polyfill. No more warnings (in my own code).
There was a problem hiding this comment.
It's for use with older versions of React. It's not to deal with deprecation warnings, it's to polyfill those lifecycle methods for React <= 16.2.
There was a problem hiding this comment.
Ah right, didn't think it that way around.
That brings me to a question for my own lib. What if I want to support the new and old Context API I guess I could just check if React.createContext is a function and then use it if avail?
There was a problem hiding this comment.
There was a problem hiding this comment.
New context API is probably going to require breaking changes to React Redux's public API for supporting multiple stores, making it a major version bump.
src/components/connectAdvanced.js
Outdated
|
|
||
| this.initSelector() | ||
| this.state = { | ||
| selector: this.createSelector() |
There was a problem hiding this comment.
I haven't looked at what StrictMode warns about yet. Does it complain about instance variables? Is that why we're putting the selector into state?
There was a problem hiding this comment.
No it doesn't.
This is because getDerivedStateFromProps is static, so one can't access instances from it
There was a problem hiding this comment.
Ahhh, I see it now. Got it.
src/components/connectAdvanced.js
Outdated
| } | ||
|
|
||
| function getDerivedStateFromProps(nextProps, prevState) { | ||
| prevState.selector.run(nextProps) |
There was a problem hiding this comment.
This looks mutative. What does it actually do?
I'm worried that this won't be safe and then avoiding the warning just gives a false sense of security.
The method signature is intentionally "get" to indicate it should be pure.
There was a problem hiding this comment.
It's not pure but it's idempotent: when you run in twice, it has the same effect as if it was just once.
I can try to make it pure by moving all the fields from selector to state though.
There was a problem hiding this comment.
Did that. It required some minor changes in tests: a7ba298#diff-b5fd7a42ea1b8efa382416b4a323003c
It's quite clear why setState calls count changed, but as for mapStateToPropsCalls, I'm not so confident
|
Well, now that the changes are becoming more significant, I wonder if we should pick #856 back up. |
|
I'm testing with this fork and components subscribed to redux state using |
|
@peacechen it works OK on my project. Can you share some parts of your setup (maybe as a reproduction repo), so that I could debug it? |
|
It's a pretty large app. I'll try to create a small sample project to recreate the behavior. |
timdorr
left a comment
There was a problem hiding this comment.
I'll pull this into some apps to see what breaks. But I'm not seeing any major concerns with the changes proposed.
I would be interested in combining with #856 to move to a full React 16 dep. We still need to do 16.0-16.2 support, so the polyfill is necessary. But I don't consider that a huge issue for the moment.
|
Yeah, I suspect there's a lot of overlap between the two. I assume this would probably merit a v6.0 major version? So, notionally v6 would be "compat with React 16.3+", and v7 would be "super-duper React async rendering awesomeness" . |
|
6.0 would be 16+. This supports <16.2, and Jim's PR does 16+. So, 16.0-16.2 would be covered. Definitely a major, though. |
|
Anyone else want to second this? I can push a 5.1.0-beta.1 to give it a whirl elsewhere. |
|
I could try to integrate it into a small project of mine and leave some feedback, once the beta is out on npm. |
|
OK, I'm going to merge this in and push a 5.1.0-test.1 release. Please give this a whirl! We can look into some of the BC-breaking stuff next. |
|
Found a big bug with the gDSFP change in 16.4: https://reactjs.org/blog/2018/05/23/react-v-16-4.html#bugfix-for-getderivedstatefromprops Because it's getting called for any render, it's getting double-called for most updates. That leads to it setting the sCU flag to true and then false on the 2nd call. I've got to do a deeper dive, but I don't have time at the moment. |
|
Well, I think (hope) it's just an issue with our test suite. So, |
* Reformat to make VS Code less annoying * Failing test in <StrictMode> * Remove usages of async-unsafe lifecycle methods * Remove usage of UNSAFE_componentWillMount in test * Move `selector` to state in order to be able to use gDSFP * codeDIdCommit * Stop using mutation * Upgrade react-lifecycles-compat
* Reformat to make VS Code less annoying * Failing test in <StrictMode> * Remove usages of async-unsafe lifecycle methods * Remove usage of UNSAFE_componentWillMount in test * Move `selector` to state in order to be able to use gDSFP * codeDIdCommit * Stop using mutation * Upgrade react-lifecycles-compat
Fixes #897