Let's take following example with an inline reducer:
const App = () => {
const [state, dispatch] = React.useReducer(s => {
console.log("reducer invoked with state", s)
return s + 1
}, 0);
return (
<div>
<p>{state}</p>
<button onClick={dispatch}>Increment</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
On first click, App is rendered twice, subsequent clicks cause only one re-render.
I would like to understand above behavior of useReducer. After having read this answer, some things are still not clear to me.
useReducer? By putting the reducer function inside the component, you make it so each time the component renders a new function is created. It may have the same text, but react can't tell that, so it's forced to run the old and new functions and compare their results.
In the following snippet i've made the reducer function log out which instance of the function is running, and you'll see that those first two double-calls are two different functions. I'm not sure why it doesn't need to also do this on later times
let count = 0;
const App = () => {
count++;
const [state, dispatch] = React.useReducer(s => {
console.log(`reducer #${count} invoked with state`, s)
return s + 1
}, 0);
return (
<div>
<p>{state}</p>
<button onClick={dispatch}>Increment</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
So yes, using an inline reducer can reducer performance a little bit. As a result, if you don't need to inline it, then you should move it outside the component.
If you do need to inline it (say, because you need to refer to other variables inside the component), it's probably not a big deal in most cases. If it is, then you can useCallback to memoize it and only change it when needed.
const Example = () => {
const [size, setSize] = useState(1);
const reduction = useCallback((s) => {
console.log(`reducer called; something = ${something}`);
return s + size;
}, [something]l
const [state, dispatch] = useReducer(reduction, 0);
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