Nick Viatick
Nick Viatick

Reputation: 265

React Hooks - useCallback performance

Im writing my product in React Hooks and yes, Im just new to it.

Today I have math about useCallback performance.This makes me consider a lot to use useCallback or not use.

Let have a look. As we know, useCallback is use for better performance.

function MainScreen() {
  const [email, setEmail] = useState("");
  const [pwd, setPwd] = useState(""):

  const onAuthenticate = useCallback(() => {
    MyApi.authenticate(email, pwd);
  }, [email, pwd]);

  return <div>
    <MyCustomButton onPress={onAuthenticate}>LOGIN</MyCustomButton>
  </div>;
}

In the example above, let's assume there are two inputs of email and password then MyCustomButton will be rendered all the times email or password changes. I tried to use useCallback to reduce number times of render but for me, it is not good enough.

Later, I figured out a way, take out email and pwd in dependencies and use useRef to hold value of email and password.

function MainScreen() {
  const [email, setEmail] = useState("");
  const [pwd, setPwd] = useState(""):

  const emailRef = useRef(email);
  const pwdRef = useRef(pwd);

  const onAuthenticate = useCallback(() => {
    MyApi.authenticate(emailRef.current, pwdRef.current);
  }, []);

  useEffect(() => {
    emailRef.current = email;
    pwdRef.current = pwd;
  }, [email, pwd]);

  return <div>
    <MyCustomButton onPress={onAuthenticate}>LOGIN</MyCustomButton>
  </div>;
}

With this approach, it stops rendering in MyCustomButton every time email or password changes.

Is it actually better in performance and cost? What do you think guys?

Thanks for sharing.

Upvotes: 1

Views: 2309

Answers (3)

欧阳斌
欧阳斌

Reputation: 2351

in this case, I would like use React.memo instead of useCallback. use React.memo to make sure this component will not call render cased by parent, once component call render, email or pwd have changed, so useCallback is unnecessary

function MainScreen() {
  const [email, setEmail] = useState("");
  const [pwd, setPwd] = useState(""):

  const onAuthenticate = () => {
    MyApi.authenticate(email, pwd);
  };

  return <div>
    <MyCustomButton onPress={onAuthenticate}>LOGIN</MyCustomButton>
  </div>;
}
export default React.memo(MainScreen)

Upvotes: 0

Rhaidzsal Ali
Rhaidzsal Ali

Reputation: 168

Since you are only performing an API call, I recommend not to use useCallback(). Make it a normal function instead.

You could be doing a premature optimization. You should only do performance optimization, if you are performing heavy computations on your app and you need to memoize your values.

An in-depth comparison of a normal function vs a function that uses useCallback() can be seen from here.

Upvotes: 0

Philipp
Philipp

Reputation: 1963

The issue that I am seeing with your code is not with useCallback - it's with useState.

A rule of thumb in react (whether you use hooks or not) is that the state has a direct impact on what is being displayed. If you modify the state, it means that the component should be re-rendered.

This rationale is what makes your component re-render when using useState. React assumes that email and password are things that change how your component should look like, therefore, it is being rerendered whenever you change one of their values.

If you don't actually use email and pwd in MyCustomButton, then using useRef instead of useState makes more sense.

However, the way you are using it in your second code sample doesn't make a lot of sense: You are combining useState and useRef so that when email changes (which will be the case when you use setEmail, then you update the ref with the same value. The only benefit that you get out of it is that onAuthenticate is not reconstructed every time.

It would be more beneficial to skip useState entirely, but from the code you posted, it is difficult to actually propose a different solution, as it is not clear how/when email and pwd are actually set.

Upvotes: 1

Related Questions