score:7

Accepted answer

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.

score:0

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.

score:1

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>
    );
}

score:7

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.


Related Query

More Query from same tag