When to use useCallback, useMemo and useEffect?

前端 未结 4 849
北恋
北恋 2021-01-30 23:33

What is the main difference between useCallback,useMemo and useEffect. ?.Give examples of when to use useCallback,useMemo and useEffect.

相关标签:
4条回答
  • 2021-01-30 23:54

    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.

    0 讨论(0)
  • 2021-01-31 00:05

    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

    1. Got functions that you don't want to be re-created on every component render?

    2. 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])
    
    0 讨论(0)
  • 2021-01-31 00:06

    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>

    0 讨论(0)
  • 2021-01-31 00:06

    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.

    0 讨论(0)
提交回复
热议问题