Do you want to request a feature or report a bug?
feature
What is the current behavior?
The current version of react requires lifecycles constructor and render must be pure functions and don't do any side affect.
We can only do side affects in componentDidMount.
But it's unfriendly with some frameworks which have got to memorize the order from ancestor component instance to child component instance.
In other words, it's like topological sort. Even you can reverse array to achieve this goal, But it's impossible to distinguish what's the end of this array because react doesn't provide an API to let framework knows the rendering is done.
componentDidMount are always called from child instance to ancestor instance, so react is missing an
approach which is doing side affects from top to bottom.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
https://codesandbox.io/s/wk57nm7rm5
/src/rako-react/prop.js line: 78
What is the expected behavior?
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
It can work properly in sync rendering if you do side affect in constructor, but it would cause unexpected result(memory leak) in async rendering because a node may be rendered multiple times.
I think I have the same problem.
I'm trying to create a chart with d3.js.
I will try to simplify the example as much as I can.
I've got a Chart component and inside of it a Line component.
I have created a codesandbox for that example => https://codesandbox.io/s/n517kq8680
The Chart component take 2 props: data and type which indicates what coordinate to use inside the data object (you have altitude points that are expressed in distance and in time).
You can also zoom the chart: this is managed inside the Chart component by using the state.
The Line component take all the props it needs from the Chart component and draw the line inside the chart.
That is quite simple but I want to things:
The problem here is that I need to determine, on the render phase, whether I must animate or not.
If the state has changed (zoom), I don't want to animate and if the props has changed, I want to.
getDerivedStateFromProps.shouldcomponentupdate because it not the prupose of that lifecycle method ans because my component is a PureComponent.UNSAFE_componentWillUpdate because unsafe legacy lifecycle methods are not compatible with the new component API...If someone know the solution, please let me know.
@tonai
You can compare props in getDerivedStateFromProps by mirroring them on to the state.
static getDerivedStateFromProps(nextProps, prevState) {
if (prevState.foo !== nextProps.foo) {
return {
...prevState,
foo: nextProps.foo,
fooDerivative: derive(nextProps.foo)
}
}
return null
}
If you need to perform a side-effect that should be done in componentDidUpdate to keep getDerivedStateFromProps pure (https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops)
componentDidUpdate(prevProps, prevState) {
if (prevProps.foo !== this.props.foo) {
doSideEffect()
}
}
Hi @malerba118 ,
thank you for reply.
Copying props in the state, just for the purpose of comparing them, seems like a hack to me.
And in some situation you might have a lot of props which tends to rapidly increase the complexity of your component...
In that case I prefer using UNSAFE_componentWillUpdate wich allow me to do the comparison and set a flag in the componant.
What is the reason of fooDerivative: derive(nextProps.foo) in your example ?
Seems it's impossible to provide such API because its usage scenario is limited, but I think a hook React.didRender which is making other frameworks to perceive a rendering is done is necessary.
@tonai
Here's an example of what derived data might look like. We want to know HOW the data changed so we can do something conditionally in the render. My example above was not quite accurate because if this was the case fooDerivative: derive(nextProps.foo), we could simply call derive(this.props.foo) inside of render to get the value we want. The need for getDerivedStateFromProps arises when derive is a function of nextProps and PrevProps. So it would have been more accurate to say fooDerivative: derive(nextProps.foo, prevState.foo).
https://codesandbox.io/s/n46qwq5x1l
class Expander extends React.Component {
state = {
expanding: false
};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.height !== prevState.height) {
return {
...prevState,
height: nextProps.height,
expanding: nextProps.height > prevState.height
};
}
return null;
}
render() {
return (
<div
style={{
height: this.props.height,
transition: `height ${this.state.expanding ? 5 : 1}s`,
overflow: "hidden"
}}
>
{this.props.children}
</div>
);
}
}
Thanks @malerba118 for your example.
In fact it would be great if getDerivedStateFromProps could have access to the next and prev values for props and state (as previous API componentWillUpdate did).
To me getDerivedStateFromProps seems more like a regression of the API since it enforce you to do some trick, like copying props into the state, o achieve what you want...
Seems it's impossible to provide such API because its usage scenario is limited, but I think a hook
React.didRenderwhich is making other frameworks to perceive a rendering is done is necessary.
In addition, React.beforeRender for doing some initialization. They can be simplify to one API like useEffect.
js
React.subscribeRender(() => {
// beforeRender
return () => {
// didRender
}
})
I think React is not flexible enough because it doesn't provide enough hooks APIs for more lower-level developers.
Seems it's impossible to provide such API because its usage scenario is limited, but I think a hook
React.didRenderwhich is making other frameworks to perceive a rendering is done is necessary.In addition,
React.beforeRenderfor doing some initialization. They can be simplify to one API likeuseEffect.React.subscribeRender(() => { // beforeRender return () => { // didRender } })I think React is not flexible enough because it doesn't provide enough hooks APIs for more lower-level developers.
I am tired and not going to develop for react, close it.