Ok so:
useEffect(() => {
}, [props.lang]);
What should I do inside useEffect to rerender component every time with props.lang change?
Think of your useEffect as a mix of componentDidMount, componentDidUpdate, and componentWillUnmount, as stated in the React documentation.
To behave like componentDidMount, you would need to set your useEffect like this:
useEffect(() => console.log('mounted'), []);
The first argument is a callback that will be fired based on the second argument, which is an array of values. If any of the values in that second argument change, the callback function you defined inside your useEffect will be fired.
In the example I'm showing, however, I'm passing an empty array as my second argument, and that will never be changed, so the callback function will be called once when the component mounts.
That kind of summarizes useEffect. If instead of an empty value, you have an argument, like in your case:
useEffect(() => {
}, [props.lang]);
That means that every time props.lang changes, your callback function will be called. The useEffect will not rerender your component really, unless you're managing some state inside that callback function that could fire a re-render.
UPDATE:
If you want to fire a re-render, your render function needs to have a state that you are updating in your useEffect.
For example, in here, the render function starts by showing English as the default language and in my use effect I change that language after 3 seconds, so the render is re-rendered and starts showing "spanish".
function App() {
const [lang, setLang] = useState("english");
useEffect(() => {
setTimeout(() => {
setLang("spanish");
}, 3000);
}, []);
return (
<div className="App">
<h1>Lang:</h1>
<p>{lang}</p>
</div>
);
}
Full code:
Simplest way
Add a dummy state you can toggle to always initiate a re-render.
const [rerender, setRerender] = useState(false);
useEffect(()=>{
...
setRerender(!rerender);
}, []);
And this will ensure a re-render, since components always re-render on state change.
You can call setRerender(!rerender) anywhere anytime to initiate re-render.
const [state, set] = useState(0);
useEffect(() => {
fn();
},[state])
function fn() {
setTimeout((), {
set(prev => prev + 1)
}, 3000)
}
The code above will re-render the fn function once every 3 seconds.
Related
What is the main difference between useCallback, useMemo and useEffect?
Give examples of when to use each of them.
A short explanation.
useEffect
It's the alternative for the class component lifecycle methods componentDidMount, componentWillUnmount, componentDidUpdate, etc. You can also use it to create a side effect when dependencies change, i.e. "If some variable changes, do this".
useCallback
On every render, everything that's inside a functional component will run again. If a child component has a dependency on a function from the parent component, the child will re-render every time the parent re-renders even if that function "doesn't change" (the reference changes, but what the function does won't).
It's used for optimization by avoiding unnecessary renders from the child, making the function change the reference only when dependencies change.
You should use it when a function is a dependency of a side effect e.g. useEffect.
useMemo
It will run on every render, but with cached values. It will only use new values when certain dependencies change. It's used for optimization when you have expensive computations. Here is also a good answer that explains it.
useEffect() will let you create side effects on your components based on the dependencies you send to it.
function Example() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
The example above is taken from the documentation of React. You can see that each time you click the button it will trigger an update on the count field (using setCount()) and then, the effect that depends on the count variable will trigger an update on the title of the page.
useCallback() will return a memoized callback. Normally, if you have a child component that receives a function prop, at each re-render of the parent component, this function will be re-executed; by using useCallback() you ensure that this function is only re-executed when any value on it's dependency array changes.
function ExampleChild({ callbackFunction }) {
const [value, setValue] = React.useState(0);
React.useEffect(() => {
setValue(value + 1)
}, [callbackFunction]);
return (<p>Child: {value}</p>);
}
function ExampleParent() {
const [count, setCount] = React.useState(0);
const [another, setAnother] = React.useState(0);
const countCallback = React.useCallback(() => {
return count;
}, [count]);
return (
<div>
<ExampleChild callbackFunction={countCallback} />
<button onClick={() => setCount(count + 1)}>
Change callback
</button>
<button onClick={() => setAnother(another + 1)}>
Do not change callback
</button>
</div>
)
}
ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
useMemo() will return a memoized value that is the result of the passed parameter. It means that useMemo() will make the calculation for some parameter once and it will then return the same result for the same parameter from a cache.
This is very useful when you need to process a huge amount of data.
function ExampleChild({ value }) {
const [childValue, setChildValue] = React.useState(0);
React.useEffect(() => {
setChildValue(childValue + 1);
}, [value])
return <p>Child value: {childValue}</p>;
}
function ExampleParent() {
const [value, setValue] = React.useState(0);
const heavyProcessing = () => {
// Do some heavy processing with the parameter
console.log(`Cached memo: ${value}`);
return value;
};
const memoizedResult = React.useMemo(heavyProcessing, [value]);
return (
<div>
<ExampleChild value={memoizedResult} />
<button onClick={() => setValue(value + 1)}>
Change memo
</button>
</div>
)
}
ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
Most minimal explanation:
useEffect:
Whenever you have some logic that is executed as reaction to a state change or before a change is about to happen.
useEffect(() => {
// execute when state changed
() => {
// execute before state is changed
}
}, [state]);
or in case of no dependency:
useEffect(() => {
// execute when component has mounted
() => {
// execute when component will unmount
}
}, []);
useCallback:
Whenever you have a function that is depending on certain states. This hook is for performance optimization and prevents a function inside your component to be reassigned unless the depending state is changed.
const myFunction = useCallback(() => {
// execute your logic for myFunction
}, [state]);
Without useCallback, myFunction will be reassigned on every render. Therefore it uses more compute time as it would with useCallback.
useMemo
Whenever you have a value that is depending on certain state. Same as useCallback, useMemo is ment to reduce reassignments for performance optimization.
const myValue = useMemo(() => {
// return calculated value
}, [state]);
Same as useCallback, myValue is only assigned when state is changing and therefore will reduce compute time. Otherwise myValue will be reassigned on every render.
!Trick to mimick componentWillMount lifecycle
useMemo(() => {
// execute componentWillMount logic
]}, []);
Since useEffect is called after the first render and then on every dependency change. It never runs before the first render.
useMemo is executed inline with your JS therefore will be executed before it reaches your Components return statement.
!NOTE: functions with useCallback and values with useMemo can be used as dependency in useCallback, useMemo and useEffect. It is highly recommended to use these hooks in order to have a well structured and readable flow of state in your component. These hooks do not trigger a render. Only useState and useReducer do!
If you want to keep state that doesnt trigger a rerender or any of the above explained hooks you can use useRef. useRef will keep a value consistent over renders without triggering any state dependent value or effect.
It's all well and good to know when to use the functions, but I wanted to know what the actual difference was between them! Here is what I found:
useMemo runs the code immediately, so the return value is available to code that comes after after it. This means it runs before the first render, so any useRef you are using to access HTML components won't be available on the initial run. (But you can add ref.current to the useMemo dependencies to have the useMemo code run again after the first render, when the useRef value has become available). Since the return value is available to code directly following it, this is why it is recommended for complex calculations that don't need to re-run on each render, as having the return value available immediately saves you from having to mess with the state to store the value now and access it later - just grab the return value of useMemo() and use it right away.
useEffect does not run immediately but runs after the first render. This means any useRef values referring to HTML elements will be valid on the first run. Since it runs after all the code in your function has finished and rendered, there is no point having a return value as there is no further code running that could use it. The only way useEffect code can do anything visible is by either changing the state to cause a re-render, or modifying the DOM directly.
useCallback is the same as useMemo except that it remembers the function itself rather than its return value. This means a useCallback function does not run immediately but can be run later (or not run at all), while useMemo runs its function immediately and just saves its return value for later use. Unlike useMemo this is not good for complex calculations as the code will run again every time it is used. If you ever pass a callback function as a prop to another component in your render function, make sure you're passing the return value of useCallback. If you make your callback function like const onClick = () => { ... } or in JSX as onClick={() => { ... }} then every render you will get a new instance of the function, so the child component will always re-render as it thinks you're changing the callback to a different function on every single render. But useCallback returns the same instance of the function each time, so the child function may skip the render completely if nothing else changed, making your app more responsive.
For example, if we pass the same function to both useMemo and useCallback:
let input = 123;
const output = useMemo(() => {
return input + 1;
}, [
input,
]);
// The above function has now run and its return value is available.
console.log( output ); // 124
input = 125; // no effect as the function has already run
console.log( output ); // 124
let input = 123;
const output = useCallback(() => {
return input + 1;
}, [
input,
]);
// The above function has not run yet but we can run it now.
console.log( output() ); // 124
input = 125; // changes the result as the function is running again
console.log( output() ); // 126
Here, useCallback has remembered the function and will keep returning the original function on future renders until the dependencies change, while useMemo actually runs the function immediately and just remembers its return value.
Both useCallback() and useMemo() provide return values that can be used immediately, while useEffect() does not because its code does not run until much later, after the render has completed.
useEffect
Gets called when the component mounts, unmounts and any of it's dependencies change.
Can be used to get data when component is mounted, subscribe and unsubscribe to event streams when component mounts and unmounts (think rxjs).
const [userId, updateUser] = useState(1);
useEffect(()=>{
//subscription
const sub = getUser(userId).subscribe(user => user);
// cleanup
return () => {
sub.unsubscribe();
}
},[userId]) // <-- Will get called again when userId changes
Can also be used for onetime method call which require no cleanup
useEffect(()=>{
oneTimeData();
},[]); // pass empty array to prevent being called multiple times
useCallback
Got functions that you don't want to be re-created on every component render?
Want a function that isn't called on component mount or unmount?
Use useCallback
const [val, updateValue] = useState(0);
const Compo = () => {
/* inc and dec will be re-created on every component render.
Not desirable a function does very intensive work.
*/
const inc = () => updateValue(x => x + 1);
const dec = () => updateValue(x => x - 1);
return render() {
<Comp1 onClick={inc} />
<Comp2 onClick={dec} />
}
}
useCallback to the rescue
const [val, updateValue] = useState(0);
const Compo = () => {
const callbackInc = useCallback(() => {
setCount(currentVal => currentVal + 1);
}, []);
const callbackDec = useCallback(() => {
setCount(currentVal => currentVal - 1);
}, []);
return render() {
<Comp1 onClick={callbackInc} />
<Comp2 onClick={callbackDec} />
}
}
If the argument passed to setCount isn't a function, then the variables you would want useCallback to 'watch' out for must be specified in the dependencies array less there will be no change effect.
const callbackInc = useCallback(() => {
setCount(val + 1); // val is an 'outside' variable therefore must be specified as a dependency
}, [val]);
useMemo
Doing heavy processing and want to memoize (cache) the results? Use useMemo
/*
heavyProcessFunc will only be called again when either val or val2 changes
*/
const result = useMemo(heavyProcessFunc(val, val2),[val,val2])
All of these hooks have the same goal: avoiding redundant component rebuilds (and re-execution of the stuff inside the hooks).
useEffect returns nothing (void) and thus is suitable for such cases.
useCallback returns a function which will be used later in the component. Unlike normal function declaration, it will not trigger component rebuild unless its dependencies change.
useMemo is just another flavour of useCallback.
Here is the best explanation I've seen so far.
I have a function below which i used as an array dependency to a useEffect handler
const handleInputUpdate = (event) => {
const eventValue = event.target.value;
setState({ ...state, answer_text: eventValue, trigger: true })
// console.log("I am changing for no reason")
}
Below is the useEffect handler
useEffect(() => console.log(" I am changing for no reason in useeffect"), [handleInputUpdate])
What i want is the useEffect handler to run only when the handleInputUpdate function is called but it runs also on component mount.
Here's what i've observed
The handleInputUpdate function doesn't run on component mount but only i need it to
Without respect to the above observation, the useEffect handler runs anyway.
Here's what i've tried
I tried consoling a text inside the handleInputUpdate function to see whether it runs on component render but it doesn't.
Even though the function doesn't run, the useEffect handler triggers anyway which is not what i want.
How can i solve this ?
Thanks in advance
useEffect dependency array is not used to trigger the effect when a function is called; the elements of the array are observed for any change and then trigger the effect.
In this case, handleInputUpdate will change on every render because it is not memoised, so the effect will also run on every render.
Since handleInputUpdate changes the state when it is called, you are better off adding that state to your useEffect dependency array:
useEffect(() => {
if (answer_text && trigger) {
console.log("I am changing for a reason in useeffect")
}
}, [answer_text, trigger])
The handleInputUpdate function, while it doesn't run on render, looks like it's created when the component runs, just before rendering. Since it won't be === to the value last in the dependency array - the handleInputUpdate from the prior render - the effect callback will run.
You need to observe changes to the answer_text value in state instead.
useEffect(() => {
// ...
}, [state.answer_text]);
I would also recommend separating out your state into different variables - these aren't class components, don't feel like you have to mash everything together into a single object structure.
const [text, setText] = useState('');
What's the different between useEffect when you pass it dependencies as the second parameter and useCallback?
Don't both essentially run the function/code passed as the first parameter whenever the dependencies passed as the second parameter change?
From what I've read the two hooks are intended to serve different purposes, but my question is whether they in actuality could be used interchangeably because they functionally do the same thing
They're too different.
useEffect will run the function inside when the dependency array changes.
useCallback will create a new function when the dependency array changes.
You can't switch useEffect with useCallback alone because you also need the logic to run the newly created function. (I suppose you could implement this if you used a ref as well, but that'd be quite strange.)
You can't switch useCallback with useEffect because you very often don't want to run the newly created function immediately - rather, you usually want to pass it as a prop to some other component.
useCallback primarily exists for optimization purposes, to reduce re-renders of a child component.
No, They are not same.
useEffect - is used to run side effects in the component when something changes. useEffect does
not return you anything. It just runs a piece of code in the component.
useCallback - Whereas useCallback returns a function, it does not execute the code actually. It is important to understand that
functions are objects in Javascript. If you don't use useCallback, the function you define inside the component is
re-created whenever the component rebuilds.
Example
Consider this example, this component will go in a infinite loop. Think Why?
const TestComponent = props => {
const testFunction = () => {
// does something.
};
useEffect(() => {
testFunction();
// The effect calls testFunction, hence it should declare it as a dependency
// Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
}, [testFunction]);
};
Because on each render the testFunction
would be re-created and we already know that ueEffect will run the code when ever the testFunction changes. And since testFunction changes on each render, the useEffect will keep on running, and hence an infinite loop.
To fix this, we have to tell react, hey please don't re-create the testFunction on each render, create it only on first render (or when something changes on which it depends).
const TestComponent = props => {
const testFunction = useCallback(() => {
// does something.
}, []);
useEffect(() => {
testFunction();
// The effect calls testFunction, hence it should declare it as a dependency
// Otherwise, if something about testFunction changes (e.g. the data it uses), the effect would run the outdated version of testFunction
}, [testFunction]);
};
This won't be a infinite loop, since instance of testFunction will change only on first render and hence useEffect will run only once.
useEffect will run the function inside when the dependency array changes.
useCallback will create a new function when the dependency array changes.
Let's take an example, If I run the below code and click the first button it'll always rerender MemoComponent as well. Why because every time
we are passing new onClick function to this. To avoid re-rendering of MemoComponent what we can do is wrap onClick to useCallback. Whenever you want to create a new function pass state to the dependence array.
If you want to perform some action on state change you can write inside useEffect.
const Button = ({ onClick }) => {
console.log("Render");
return <button onClick={onClick}>Click</button>;
};
const MemoComponent = React.memo(Button);
export default function Home() {
const [state, setState] = useState(1);
useEffect(() => {
console.log(state); // this will execute when state changes
}, [state]);
const onClick = () => {};
// const onClick = useCallback(() => {},[])
return (
<main>
<button onClick={() => setState(1 + state)}>{state}</button>
<MemoComponent onClick={onClick} />
</main>
);
}
useEffect
It's the alternative for the class component lifecycle methods componentDidMount, componentWillUnmount, componentDidUpdate, etc. You can also use it to create a side effect when dependencies change, i.e. "If some variable changes, do this".
Whenever you have some logic that is executed as reaction to a state change or before a change is about to happen.
useEffect(() => {
// execute when state changed
() => {
// execute before state is changed
}
}, [state]);
OR
useEffect(() => {
// execute when state changed
() => {
// execute before state is changed
}
}, []);
useCallback
On every render, everything that's inside a functional component will run again. If a child component has a dependency on a function from the parent component, the child will re-render every time the parent re-renders even if that function "doesn't change" (the reference changes, but what the function does won't).
It's used for optimization by avoiding unnecessary renders from the child, making the function change the reference only when dependencies change. You should use it when a function is a dependency of a side effect e.g. useEffect.
Whenever you have a function that is depending on certain states. This hook is for performance optimization and prevents a function inside your component to be reassigned unless the depending state is changed.
const myFunction = useCallback(() => {
// execute your logic for myFunction
}, [state]);
Without useCallback, myFunction will be reassigned on every render. Therefore it uses more compute time as it would with useCallback.
Even though I'm working with React for some time, I can't figure this out. Why is the empty UseEffect causing component to re-render? The thing is I get two console.logs. Tnx!
function App() {
useEffect(() => {
}, [])
console.log('render')
return (
<h1>Hello world</h1>
);
}
Empty useEffect subscribed to all the component's props.
useEffect(() => console.log('rerendered due to new props'));
Any useEffect works at least once after first component's render. So you can use it like componentDidMount.
If you want to use it like componentDidMount only, you have to pass an empty array as the second param.
useEffect(() => console.log('after first render'), []);
Subscribe to a specific prop:
useEffect(() => console.log(' after first render or message updated', props.message), [props.message]);
What is the main difference between useCallback, useMemo and useEffect?
Give examples of when to use each of them.
A short explanation.
useEffect
It's the alternative for the class component lifecycle methods componentDidMount, componentWillUnmount, componentDidUpdate, etc. You can also use it to create a side effect when dependencies change, i.e. "If some variable changes, do this".
useCallback
On every render, everything that's inside a functional component will run again. If a child component has a dependency on a function from the parent component, the child will re-render every time the parent re-renders even if that function "doesn't change" (the reference changes, but what the function does won't).
It's used for optimization by avoiding unnecessary renders from the child, making the function change the reference only when dependencies change.
You should use it when a function is a dependency of a side effect e.g. useEffect.
useMemo
It will run on every render, but with cached values. It will only use new values when certain dependencies change. It's used for optimization when you have expensive computations. Here is also a good answer that explains it.
useEffect() will let you create side effects on your components based on the dependencies you send to it.
function Example() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
The example above is taken from the documentation of React. You can see that each time you click the button it will trigger an update on the count field (using setCount()) and then, the effect that depends on the count variable will trigger an update on the title of the page.
useCallback() will return a memoized callback. Normally, if you have a child component that receives a function prop, at each re-render of the parent component, this function will be re-executed; by using useCallback() you ensure that this function is only re-executed when any value on it's dependency array changes.
function ExampleChild({ callbackFunction }) {
const [value, setValue] = React.useState(0);
React.useEffect(() => {
setValue(value + 1)
}, [callbackFunction]);
return (<p>Child: {value}</p>);
}
function ExampleParent() {
const [count, setCount] = React.useState(0);
const [another, setAnother] = React.useState(0);
const countCallback = React.useCallback(() => {
return count;
}, [count]);
return (
<div>
<ExampleChild callbackFunction={countCallback} />
<button onClick={() => setCount(count + 1)}>
Change callback
</button>
<button onClick={() => setAnother(another + 1)}>
Do not change callback
</button>
</div>
)
}
ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
useMemo() will return a memoized value that is the result of the passed parameter. It means that useMemo() will make the calculation for some parameter once and it will then return the same result for the same parameter from a cache.
This is very useful when you need to process a huge amount of data.
function ExampleChild({ value }) {
const [childValue, setChildValue] = React.useState(0);
React.useEffect(() => {
setChildValue(childValue + 1);
}, [value])
return <p>Child value: {childValue}</p>;
}
function ExampleParent() {
const [value, setValue] = React.useState(0);
const heavyProcessing = () => {
// Do some heavy processing with the parameter
console.log(`Cached memo: ${value}`);
return value;
};
const memoizedResult = React.useMemo(heavyProcessing, [value]);
return (
<div>
<ExampleChild value={memoizedResult} />
<button onClick={() => setValue(value + 1)}>
Change memo
</button>
</div>
)
}
ReactDOM.render(<ExampleParent />, document.getElementById('root'));
<script src="https://unpkg.com/react#16.8.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.8.0/umd/react-dom.development.js"></script>
<div id="root"></div>
Most minimal explanation:
useEffect:
Whenever you have some logic that is executed as reaction to a state change or before a change is about to happen.
useEffect(() => {
// execute when state changed
() => {
// execute before state is changed
}
}, [state]);
or in case of no dependency:
useEffect(() => {
// execute when component has mounted
() => {
// execute when component will unmount
}
}, []);
useCallback:
Whenever you have a function that is depending on certain states. This hook is for performance optimization and prevents a function inside your component to be reassigned unless the depending state is changed.
const myFunction = useCallback(() => {
// execute your logic for myFunction
}, [state]);
Without useCallback, myFunction will be reassigned on every render. Therefore it uses more compute time as it would with useCallback.
useMemo
Whenever you have a value that is depending on certain state. Same as useCallback, useMemo is ment to reduce reassignments for performance optimization.
const myValue = useMemo(() => {
// return calculated value
}, [state]);
Same as useCallback, myValue is only assigned when state is changing and therefore will reduce compute time. Otherwise myValue will be reassigned on every render.
!Trick to mimick componentWillMount lifecycle
useMemo(() => {
// execute componentWillMount logic
]}, []);
Since useEffect is called after the first render and then on every dependency change. It never runs before the first render.
useMemo is executed inline with your JS therefore will be executed before it reaches your Components return statement.
!NOTE: functions with useCallback and values with useMemo can be used as dependency in useCallback, useMemo and useEffect. It is highly recommended to use these hooks in order to have a well structured and readable flow of state in your component. These hooks do not trigger a render. Only useState and useReducer do!
If you want to keep state that doesnt trigger a rerender or any of the above explained hooks you can use useRef. useRef will keep a value consistent over renders without triggering any state dependent value or effect.
It's all well and good to know when to use the functions, but I wanted to know what the actual difference was between them! Here is what I found:
useMemo runs the code immediately, so the return value is available to code that comes after after it. This means it runs before the first render, so any useRef you are using to access HTML components won't be available on the initial run. (But you can add ref.current to the useMemo dependencies to have the useMemo code run again after the first render, when the useRef value has become available). Since the return value is available to code directly following it, this is why it is recommended for complex calculations that don't need to re-run on each render, as having the return value available immediately saves you from having to mess with the state to store the value now and access it later - just grab the return value of useMemo() and use it right away.
useEffect does not run immediately but runs after the first render. This means any useRef values referring to HTML elements will be valid on the first run. Since it runs after all the code in your function has finished and rendered, there is no point having a return value as there is no further code running that could use it. The only way useEffect code can do anything visible is by either changing the state to cause a re-render, or modifying the DOM directly.
useCallback is the same as useMemo except that it remembers the function itself rather than its return value. This means a useCallback function does not run immediately but can be run later (or not run at all), while useMemo runs its function immediately and just saves its return value for later use. Unlike useMemo this is not good for complex calculations as the code will run again every time it is used. If you ever pass a callback function as a prop to another component in your render function, make sure you're passing the return value of useCallback. If you make your callback function like const onClick = () => { ... } or in JSX as onClick={() => { ... }} then every render you will get a new instance of the function, so the child component will always re-render as it thinks you're changing the callback to a different function on every single render. But useCallback returns the same instance of the function each time, so the child function may skip the render completely if nothing else changed, making your app more responsive.
For example, if we pass the same function to both useMemo and useCallback:
let input = 123;
const output = useMemo(() => {
return input + 1;
}, [
input,
]);
// The above function has now run and its return value is available.
console.log( output ); // 124
input = 125; // no effect as the function has already run
console.log( output ); // 124
let input = 123;
const output = useCallback(() => {
return input + 1;
}, [
input,
]);
// The above function has not run yet but we can run it now.
console.log( output() ); // 124
input = 125; // changes the result as the function is running again
console.log( output() ); // 126
Here, useCallback has remembered the function and will keep returning the original function on future renders until the dependencies change, while useMemo actually runs the function immediately and just remembers its return value.
Both useCallback() and useMemo() provide return values that can be used immediately, while useEffect() does not because its code does not run until much later, after the render has completed.
useEffect
Gets called when the component mounts, unmounts and any of it's dependencies change.
Can be used to get data when component is mounted, subscribe and unsubscribe to event streams when component mounts and unmounts (think rxjs).
const [userId, updateUser] = useState(1);
useEffect(()=>{
//subscription
const sub = getUser(userId).subscribe(user => user);
// cleanup
return () => {
sub.unsubscribe();
}
},[userId]) // <-- Will get called again when userId changes
Can also be used for onetime method call which require no cleanup
useEffect(()=>{
oneTimeData();
},[]); // pass empty array to prevent being called multiple times
useCallback
Got functions that you don't want to be re-created on every component render?
Want a function that isn't called on component mount or unmount?
Use useCallback
const [val, updateValue] = useState(0);
const Compo = () => {
/* inc and dec will be re-created on every component render.
Not desirable a function does very intensive work.
*/
const inc = () => updateValue(x => x + 1);
const dec = () => updateValue(x => x - 1);
return render() {
<Comp1 onClick={inc} />
<Comp2 onClick={dec} />
}
}
useCallback to the rescue
const [val, updateValue] = useState(0);
const Compo = () => {
const callbackInc = useCallback(() => {
setCount(currentVal => currentVal + 1);
}, []);
const callbackDec = useCallback(() => {
setCount(currentVal => currentVal - 1);
}, []);
return render() {
<Comp1 onClick={callbackInc} />
<Comp2 onClick={callbackDec} />
}
}
If the argument passed to setCount isn't a function, then the variables you would want useCallback to 'watch' out for must be specified in the dependencies array less there will be no change effect.
const callbackInc = useCallback(() => {
setCount(val + 1); // val is an 'outside' variable therefore must be specified as a dependency
}, [val]);
useMemo
Doing heavy processing and want to memoize (cache) the results? Use useMemo
/*
heavyProcessFunc will only be called again when either val or val2 changes
*/
const result = useMemo(heavyProcessFunc(val, val2),[val,val2])
All of these hooks have the same goal: avoiding redundant component rebuilds (and re-execution of the stuff inside the hooks).
useEffect returns nothing (void) and thus is suitable for such cases.
useCallback returns a function which will be used later in the component. Unlike normal function declaration, it will not trigger component rebuild unless its dependencies change.
useMemo is just another flavour of useCallback.
Here is the best explanation I've seen so far.