I'm having a huge form built with react and material-ui. The form uses two way binding and update state for input changes. changing any input filed cause all components to update (obvious by react developer tools TraceReactUpdate enabled). When it comes to TextField it makes my page rendering very slow. using this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) doesn't help.
It can be extremely difficult to find issues like the above, because it totally depends on the actual code you have written. I am sure that the react rendering concept works (as it has for myself and so many others), but without seeing more code it is impossible to pinpoint the actual problem.
Still, I have a feeling that the real cause is "simple", meaning that it is very likely due to a prop being passed that has indeed changed. Maybe not in value, but in instance. IIRC, the PurerenderMixin is not comparing values (unless the data are value types), it is comparing instances. So even if the data is the same, if the instance has changed then it will re-render.
Some key-points to consider:
Are you passing just the props that you need to each component, or are you passing all props to them all?
Are the data-structures immutable?
Are you sure that you are not passing data that changes on the iterations, like passing the javascript [] as a prop will mean that the data has changed (see https://medium.com/#esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f#.hx97qk4tx for sample on how this can screw up your day).
If you explicitly create a shouldComponentUpdate() method for the components then you can control this yourself. The PureRenderMixin does a shallow check to see if the props have changed, but, if you are passing them all then no matter if they have been used or not in the render method then just one of them changing will mean that the component is considered to need to render (as in, not mount, but render in memory and reconcile possible changes with the dom). Using shouldComponentUpdate can help stop rendering based on your own checks.
Using immutable props can also be helpful. The React PureRenderMixin only does a shallow comparison, as mentioned. So, if you are passing data-structures in the props that have depth (like sub-properties), then these are not checked. Meaning that you could end up with the opposite problem you have now, that is components that should have updated but aren't. If you are using i.e. redux and have done "the right thing" and are using i.e. Immutable.js, then using the PureRenderMixin is good enough.
Reading the specific docs for this may or may not help. There's some good description of this in the React manuals: https://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action
And - I forgot to say, if you are using redux then you could consider these somewhat elegant and simple ways of handling your forms:
http://redux-form.com/
https://davidkpiano.github.io/react-redux-form/
Hope that this helps. Good luck.
Related
As you know, for the sake of good performance, we always try to minimize rendering in single page applications. For instance, in React whenever a state or props change inside a component, that change make that component re execute, re evaluate and finally re render.
So, are there any similar conditions in Angular ? and what are the best practices and patterns for reducing extra rendering ?
This is a huge topic to cover here but I would suggest the following article for starters: https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/
TLDR;
What happens is that Angular at startup time will patch several low-level browser APIs, such as for example addEventListener, which is the browser function used to register all browser events, including click handlers. Angular will replace addEventListener with a new version
So by extending base functionality, angular understands changes that trigger re-evaluation of values and rerendering needs.
As an extra, we need to mention that the comparisons are not deep inside reference types, so some handling should happen.
In the article, several methods for performance tweaking are mentioned like
On push change detection method.
Disabling automatic detection for a component and triggering the cycles manually.
Using immutable objects with the help of libraries line immutable.js
As you can understand, these being their own pitfalls and considerations
Currently my project is still using mobx#4 and mobx-react#6 and I found this warning in the documentation:
Fair warning. Don't ever use React.useMemo to keep reference to the state object. It may be randomly thrown away by React and you may lose data.(mobx-react documentation)
I can't understand it, can anyone help with an example and the reason why?
Quote from React docs:
You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.
Basically React can reinstantiate memoized value at any time if it wants to and you will lose your whole Store because it will be recreated with default parameters.
It might not do it right now, but it is better not use memo for persistent values so you won't be forced to make refactoring if you migrate to future versions of React.
Link: https://reactjs.org/docs/hooks-reference.html#usememo
This has come about because during prototyping, I'm finding that incoming new prop(s) might be an array of complex objects, so prevProps.myProp===this.props.myProp is always false. JSON.stringifying them both before comparison works, but feels unreliable.
I'm trying to write a reusable function for Class Components that compares prev/new props in react's componentDidUpdate. For example:
componentDidUpdate(prevProps) {
// First, get difference here, possibly using a lib like npm 'deep-object-diff'.
// ...or just JSON.stringify both and do string comparison
const changes = getTheDifference(prevProps, this.props)
// Don't do anything if there's no changes.
if (!changes) return
// Then I want to do something like:
this.setState( Object.assign(this.state, changes) )
}
...that would mean any time the incoming props change, those get immediately reflected in state. I'm having some issues finding a suitable diff lib, but I still feel like I shouldn't be having to do this and am missing something - is there a generally accepted "normal" way to do this, or is me having this problem just a sign of:
The component is trying to do too much/state too complex?
I should be mapping props to state with something like Redux? (trying to avoid this until absolutely necessary)
I'm overthinking it, sometimes the logic in a component's componentDidUpdate is just complex and unique?
that would mean any time the incoming props change, those get immediately reflected in state
Yes, that's wrong. When I first started out I was doing the same thing.
state is something "owned" by that component (noteworthy: not all components need state at all!).
props are something that are "owned" by a higher component.
Best example:
ComponentA passed an id to ComponentB as a prop. ComponentB uses that id to make an API request (for example).
The status/results of that API request form part of ComponentB's state (it's "owned" by your component). The id passed in as a prop is NOT part of ComponentB's state (it's owned by ComponentA, or maybe somewhere higher in the tree that passed it as a prop to ComponentA).
When the id prop changes, ComponentB will need to make another API request.
EDIT:
The complexity of lifecycle methods is why React has highly encouraged functional components.
You should think of components as functions. It's a lot easier to write the logic if you just think of it as input -> output.
componentDidUpdate has been moved to useEffect with a dependency list so you can say - run this function, but only when this prop changes - which is a nice way to break down massive componentDidUpdate methods into tiny readbale/testable chunks.
I've heard a lot of people say hooks ruined react, but I highly disagree with them. React saw the problems people were running into in the community by misusing class/instance based components and instead of lecturing about how to use them correctly, they nudged people to writing better components by introucing a simpler API - functions, while they still can and will be abused - are generally simpler to deal with than classes and align nicely with composition over inheritance and declarative over imperative.
So I started learning React a week ago and I inevitably got to the problem of state and how components are supposed to communicate with the rest of the app. I searched around and Redux seems to be the flavor of the month. I read through all the documentation and I think it's actually a pretty revolutionary idea. Here are my thoughts on it:
State is generally agreed to be pretty evil and a large source of bugs in programming. Instead of scattering it all throughout your app Redux says why not just have it all concentrated in a global state tree that you have to emit actions to change? Sounds interesting. All programs need state so let's stick it in one impure space and only modify it from within there so bugs are easy to track down. Then we can also declaratively bind individual state pieces to React components and have them auto-redraw and everything is beautiful.
However, I have two questions about this whole design. For one, why does the state tree need to be immutable? Say I don't care about time travel debugging, hot reload, and have already implemented undo/redo in my app. It just seems so cumbersome to have to do this:
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
];
Instead of this:
case COMPLETE_TODO:
state[action.index].completed = true;
Not to mention I am making an online whiteboard just to learn and every state change might be as simple as adding a brush stroke to the command list. After a while (hundreds of brush strokes) duplicating this entire array might start becoming extremely expensive and time-consuming.
I'm ok with a global state tree that is independent from the UI that is mutated via actions, but does it really need to be immutable? What's wrong with a simple implementation like this (very rough draft. wrote in 1 minute)?
var store = { items: [] };
export function getState() {
return store;
}
export function addTodo(text) {
store.items.push({ "text": text, "completed", false});
}
export function completeTodo(index) {
store.items[index].completed = true;
}
It's still a global state tree mutated via actions emitted but extremely simple and efficient.
Isn't Redux just glorified global state?
Of course it is. But the same holds for every database you have ever used. It is better to treat Redux as an in-memory database - which your components can reactively depend upon.
Immutability enables checking if any sub-tree has been altered very efficient because it simplifies down to an identity check.
Yes, your implementation is efficient, but the entire virtual dom will have to be re-rendered each time the tree is manipulated somehow.
If you are using React, it will eventually do a diff against the actual dom and perform minimal batch-optimized manipulations, but the full top-down re-rendering is still inefficient.
For an immutable tree, stateless components just have to check if the subtree(s) it depends on, differ in identities compared to previous value(s), and if so - the rendering can be avoided entirely.
Yes it is!!!
Since there is no governance of who is allowed to write a specific property/variable/entry to the store and practically you can dispatch any action from anywhere, the code tends to be harder to maintain and even spaghetti when your code base grows and/or managed by more than one person.
I had the same questions and issues with Redux when I started use it so I have created a library that fix these issue:
It is called Yassi:
Yassi solves the problems you mentioned by define a globally readable and privately writable store. It means that anyone can read a property from the store (such as in Redux but simpler).
However only the owner of the property, meaning the object that declare the property can write/update that property in the store
In addition, Yassi has other perks in it such as zero boilerplate to declare entry in the store by using annotations (use #yassit('someName'))
Update the value of that entry does not require actions/reducers or other such cumbersome code snippets, instead just update the variable like in regular object.
from the documentation here: http://facebook.github.io/react/docs/pure-render-mixin.html
The footnote is saying that you should use forceUpdate() if the structure of complexe data (deep data structure) is changed.
From the definition of a pure : it renders the same result given the same props and state.
I'm thinking more and more that this is a contradiction because if the data structure changes, it means that you are giving new props/state. Thus the component is not "pure" anymore.
In my opinion, if you change the props or state that is passed to the component you can either:
use forceUpdate().
remove PureRenderMixin from the mixins.
Thus, under the hood... you are transforming a component that is pure to a "non-pure" component. So removing PureRenderMixin should be the only option available.
Am I right ? Or a Pure component means that the component is "cached" and reused when giving the same props ?
Sorry but I'm a bit confused here.
PureRenderMixin is used to give React a way of knowing that it shouldn't call your render method unnecessarily. For example, if your render method is complex enough, it can give you a performance boost if your component isn't being re-rendered with the same props/state.
But, like it's said in the documentation, PureRenderMixin does not compare deeply nested data structures, so it might not call your render function, when it should have, because some nested structure actually changed.
In these cases, it's better to not use PureRenderMixin and use shouldComponentUpdate and perform you own comparison logic.
Also, from the docs, you should avoid using forceUpdate.
The absence of side effect is an important aspect of the mixin because it enables the logic of not rendering the component twice given the same state.
That shouldn't be a satisfying answer because, as you pointed out, nested changes won't be caught by the shallow checking... Unless your data structure are immutable!
I strongly recommend watching Lee Byron's talk on immutable data structures which explains how immutable data improves the performance of your application by avoiding a whole class of problems.
Essentially, a smart library like immutable.js will share common state between two snapshots of an immutable object.
Therefore shallow equality becomes a proof of the underlying data not being changed.