I've been learning new features of React 16.8. I believe React's Pure Component should automatically avoid unnecessary re-render operations.
In the following example, the App
itself is a stateless component. I use useState
to maintain two state objects text
and nested: {text}
.
There are 3 tests. The first 2 tests work. No matter how many times, I change the state, no re-render operation will be required.
Now, the third test tries to set the state of text
with the same string value, but the reference is different. I expect nothing to be re-rendered, but actually, the <Headline/>
will be re-rendered.
Shall I use certain memorize technique to avoid? I feel it will be too much code to archive that. And programmer must be very careful to write high-quality React code. ..
class Headline extends React.PureComponent {
render() {
const {text} = this.props;
return <h1>{text} (render time: {Date.now()})</h1>;
}
}
const simpleText = 'hello world'
const App = () => {
const [text, setText] = React.useState(simpleText)
const [nested, setNested] = React.useState({text: simpleText})
return (
<div>
<Headline text={text}/>
<Headline text={nested.text}/>
<button onClick={()=>setText(simpleText)}>
test 1: the first line should not change (expected)
</button>
<button onClick={()=>setNested({text: simpleText})}>
test 2: the second line will not change (expected)
</button>
<button onClick={()=>setText(new String(simpleText))}>
test 3: the first line will change on every click (why?)
</button>
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#app"))
Here is a live playground in jsfiddle:
https://jsfiddle.net/fL0psxwo/1/
Thank you React folks, cheers!
Update 1: Thanks Dennis for mentioning why-did-you-render
The author points some very useful articles. I think it could be very educational to everybody. https://medium.com/welldone-software/why-did-you-render-mr-big-pure-react-component-part-2-common-fixing-scenarios-667bfdec2e0f
Update 2:
I created a new hook called withDirtyCheck
so that my code will automatically do content dirty check.
import isEqual from 'lodash-es/isEqual';
export const withDirtyCheck = ([getter, setter]) => {
const setStateIfDirty = (nextState) =>
setter((prevState) => (isEqual(prevState, nextState) ? prevState : nextState));
return [getter, setStateIfDirty];
};
Checkout my latest library https://github.com/stanleyxu2005/react-einfach
The problem is that with new
operator you creating a String Object
which is always different from the previous state.
'hello world' === new String('hello world') // false, always.
'hello world' === String('hello world') // true
Check this example:
setText(prevState => {
// Will render
// const currState = new String(simpleText);
// Won't render
const currState = String(simpleText);
console.log(prevState === currState); // if true, no re-render
// if false, re-render
return currState;
});
Refer to What is the difference between string primitives and String objects in JavaScript?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With