I'm new with Redux, and I'd like to improve performances of my web app as much as possible.
I have a state in redux, that I store in a variable to display it later.
Here is the code :
const metricsState = useSelector((state: MetricsStateObject) => state.MetricsState);
const myMetrics = metricsState.myMetrics;
I saw that useMemo improve performance by not re-render if the data did not mutate.
So I'm wondering if const myMetrics = useMemo(() => metricsState.myMetrics, [metricsState.myMetrics]); is a good practice, or totaly useless ?
Thank you for your time.
useMemo is for high cost computation, you dont want to run each render. Like
const something = useMemo(()=> megaBigArray.reduce((acc,i)=>acc*i,0), [megaBigArray])
or something like that. You only calculate that variable, if megaBigArraychange.
In your case, that code will be run every render anyways, but useSelector should trigger render only, when part of store you are selecting change. So you should be good without it.
Let me talk about the conclusion first, it's totally useless.
why?
because metricsState.myMetrics is just a value-taking process and does not involve expensive calculations.
but useMemo itself consumes a certain amount of calculation.
so I think that belongs to premature optimization
I think #Wraithys answer is not correct here. I'm pretty sure, React will not compute the component with the useSelector if the state of the selector didn't change and the selector also didn't change. This means that you must memoize the selector too, otherwise React and Redux will not be able to optimize the rendering. I think you may have to also memoize the component using React.memo() for it to work fully. Also, it may be best to always state your selectors in a file so you don't have to memoize them, since they are constant.
Related
We can already detect dimension change by using ref and useEffect in React:
useEffect(() => {
console.log("height changed to", ref.current?.clientHeight)
}, [ref.current?.clientHeight])
I wonder what is the advantage of ResizeObserver over this ref + useEffect approach? I'm surprised there's no online discussion around this, given ResizeObserver has been there for awhile since 2018. I can see if you're using Vanilla Javascript then ResizeObserver might be the best way to get dynamic height.
But in React I just don't understand how ResizeObserver API is better. I tested both and in Chrome both fire updates almost at the same time. I researched online and many are talking about how to use React Hook with ResizeObserver, but rarely do these posts talk about ref + useEffect already suffice.
Does anyone know if using React, any advantage using ResizeObserver API, or it really doesn't differ much from ref + useEffect approach?
We can already detect dimension change by using ref and useEffect in React:
For a useEffect to run, the component must be rendering. For the component to be rendering, something somewhere must have set state. So if all of that is happening, then yes, your effect can notice the size has changed since the previous render.
But if nothing sets state, then none of that will happen. Maybe you're getting lucky, and some component happens to be setting state around the time the size changes, but that's not something you should rely on. If you delete some random component, or try to optimize performance by skipping rendering, you can suddenly break your resize "detection" code.
The point of the resize observer is to get notified that the change has happened. Then you can set state, and cause the rerender. So now instead of hoping a rerender happens, you know it will happen.
I am new to Redux and I have been reading quite good stuff around it, including memoization technique (especially with reselect).
I have a question though and I struggle to find a proper answer.
If we add memoization for every single selector (assuming we have a lot), even the simple getters, will it cause performance issues (due to memoized data under the hood maybe?)?
Memoization for complex selectors is obviously beneficial as it prevents recomputing if not needed.
But I find memoization for simple selectors beneficial as well, to avoid useless rerender.
In fact, I use useSelector hook and the doc states:
When an action is dispatched, useSelector() will do a reference comparison of the previous selector result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render.
So even for a selector returning the same primitive value (say an int), If i am not wrong, the useSelector should always make the component rerender (even if the selector always returns the same value).
If what I am saying is ture, memoizing even simple getters is usefull for that matter, but can overusing it cause other performance issues?
Thanks for helping
Writing memoized selector functions is useful, but many people try to memoize too many selectors which really shouldn't be memoized.
If a selector function just does a simple lookup and return of existing data from the state, there's no need to memoize it - it could just be a simple function. For example:
const selectTodoById = (state, id) => state.todos.entities[id];
Second, you also probably shouldn't create a separate selector for every single state field. Find a reasonable level of granularity.
Memoized selectors are only useful when the selector returns some derived data. A good example of this is filtering an array:
const selectCompletedTodos = createSelector(
state => state.todos,
state => state.filters.completed,
(todos, completed) => todos.filter(t => t.completed === completed)
);
That way, the derived data is only re-calculated when the input values change.
As a side note, I actually am planning to write a new Redux core docs page with guidance and usage information on when and how to write memoized selectors. Until then, you can read my post Using Reselect Selectors for Encapsulation and Performance , which covers a lot of that material already.
Defining a calculated (initialized) constant using React hooks can be performed in two ways that seem functionally equivalent. I don't want to get into the use cases for this, but suffice to say that there are cases where a constant value can be derived from initial props or state that isn't expected to change (think route data, bound dispatch, etc).
First, useState
const [calculatedConstant] = useState(calculateConstantFactory);
Second, useMemo
const calculatedConstant = useMemo(calculateConstantFactory, []);
Both of these seem functionally equivalent, but without reading the source code, I'm not sure which is better in terms of performance or other considerations.
Has anyone done the leg work on this? Which would you use and why?
Also, I know some people will recoil at the assumption that state can be "considered constant". I'm not sure what to tell you there. But even without state, I may want to define a constant within a component that has no state at all, for example, creating a block of JSX that doesn't change.
I could define this outside of the component, but then it's consuming memory, even when the component in question is not instantiated anywhere in the app. To fix this, I would have to create a memoization function and then manually release the internal memoized state. That's an awful lot of hassle for something hooks give us for free.
Edit: Added examples of the approaches talked about in this discussion.
https://codesandbox.io/s/cranky-platform-2b15l
You may rely on useMemo as a performance optimization, not as a semantic guarantee
Meaning, semantically useMemo is not the correct approach; you are using it for the wrong reason. So even though it works as intended now, you are using it incorrectly and it could lead to unpredictable behavior in the future.
useState is only the correct choice if you don't want your rendering to be blocked while the value is being computed.
If the value isn't needed in the first render of the component, you could use useRef and useEffect together:
const calculatedConstant = useRef(null);
useEffect(() => {
calculatedConstant.current = calculateConstantFactory()
}, [])
// use the value in calcaulatedConstant.current
This is the same as initializing an instance field in componentDidMount. And it doesn't block your layout / paint while the factory function is being run. Performance-wise, I doubt any benchmark would show a significant difference.
The problem is that after initializing the ref, the component won't update to reflect this value (which is the whole purpose of a ref).
If you absolutely need the value to be used on the component's first render, you can do this:
const calculatedConstant = useRef(null);
if (!calculatedConstant.current) {
calculatedConstant.current = calculateConstantFactory();
}
// use the value in calculatedConstant.current;
This one will block your component from rendering before the value is set up.
If you don't want rendering to be blocked, you need useState together with useEffect:
const [calculated, setCalculated] = useState();
useEffect(() => {
setCalculated(calculateConstantFactory())
}, [])
// use the value in calculated
Basically if you need the component to re-render itself: use state. If that's not necessary, use a ref.
I've been building quite an extensive app with React, Redux and Normalizr but have been struggling with a totally excessive number of redundant render cycles, and am now thinking I've perhaps misunderstood how to combine mapStateToProps and Normalizr.
In my mapStateToProps, I'm referencing all of a certain entity type, which I can then use to get an entity from its ID:
function mapStateToProps(state) {
return {
allMilestones: state.account.entities.milestones,
allTasks: state.account.entities.tasks,
}
}
Using the above mapStateToProps, whenever I need to get an entity, I can just go (for example) const taskObject = this.props.allTasks[taskId]. Quick and convenient, but I understand this means there's a lot of props being passed around - I thought passing around references wouldn't be a big deal, but then I noticed everything was re-rendering just, all the time.
Would this be a likely culprit for an unreasonable amount of render cycles?
If so, could I expect implementing Reselect for all of these cases would positively affect performance?
It's possible but this is a guesstimation without benchmarks (and you should try to clarify that yourself before making any optimisations). React-Redux will do a comparison of all of the keys of the object returned from mapStateToProps and will rerender if any are different.
If the reference changes each time - because you're using an immutable Map, for example - then the component will re-render any time mapStateToProps() is called.
You should try to make the return value more stable by only returning what is required by the connected component.
https://react-redux.js.org/using-react-redux/connect-mapstate#return-values-determine-if-your-component-re-renders
I would like to pass to the redux connect 'mapStateToProps' function the entire global state
The, inside my components i can just access the state which is now the global state.
Is there anything wrong with that?
I don't want to slice the state into many chunks and give it sliced to each component but just give the entire global state.
Are there any performance problems with that ? I understand that it re-renders the entire component but with react's diffing algorithm i imagine it should be fine.
Using a 'this.props.count' is not as suggestive as doing a 'this.props.todoSection.count. Just a readability thing.
I read that 'time-slicing api' in react 1.6 could potentially improve the various performance problems related to mantaining a global state.
https://auth0.com/blog/time-slice-suspense-react16/
Technically it's possible, but the better practice is to create mapToStateProps in each component which using global state. And map the only needed props in it.
And then what? whenever something change anywhere in the state, regardless if its related to your component or not your component would rerender?
why would you ever want something like that? (just curious)
It sounds like you don't want to map the entire global state, just the relevant reducer. So you certainly could map just that one store:
const mapStateToProps = ({ todoStore }) => ({ todoStore });
That'd be much less costly than mapping the whole store, but at scale it could start causing performance issues across your app if the store gets big enough (and/or the end-user's browser is crappy enough). At best it's an antipattern.
Using a this.props.count is not as suggestive as doing a this.props.todoStore.count. Just a readability thing.
You could always namespace while still mapping only the data you need:
const mapStateToProps = ({ todoStore: { count, foo } }) => ({ todoStore: { count, foo } });
That'd give you the shape you want while only connecting the state required. But comes with the slight developer cost of repeating the property names - and still requires defining what state to map - which maybe defeats the purpose.