Home > front end >  useCallback not giving the required effect i need in my program
useCallback not giving the required effect i need in my program

Time:07-23

In the following code; as per my knowledege about useCallback hook 'rerendering has happened!' message should be displayed only when i am typing something inside the input field and shouldn't be printed when I am clicking on the Toggle button. But the message does print for the 2nd case. Why?

my App.js file

import {useState, useCallback} from 'react'
import List from './List'

function App() {
  const [a, seta] = useState('')
  const [Color, setColor] = useState("#12ab34")

  const message = useCallback(() => {
    console.log('rerendering has happened!')
    return [a 'SAMSUNG', a 'MOTO', a 'NOKIA']
  }, [a])

  return (
    <div className="App">
      <input value={a} onChange={e => seta(e.target.value)} />
      <button onClick={() => Color === "#12ab34" ? setColor("#abb111") : setColor("#12ab34") }>toggle</button>
      <List message={message()} Color={Color}/>
    </div>
  );
}

export default App;

my List.js file

import React from 'react'

export default function List({message, Color}){
    return (<>
    <ul>
    <li style={{color: Color}}>{message[0]}</li>
    <li style={{color: Color}}>{message[1]}</li>
    <li style={{color: Color}}>{message[2]}</li>
    </ul>
</>)
}

CodePudding user response:

Your function is not created multiple times don't worry. The log statement

'rerendering has happened!'

is running multiple times. It is because your function message() runs multiple times.

Look at <List message={message()} Color={Color}/>. What you want to do is memoize the value returned from your function, and do not call it unnecessarily.

import { useState, useCallback, useMemo } from "react";
import List from "./List";

function App() {
  const [a, seta] = useState("");
  const [Color, setColor] = useState("#12ab34");
  console.log({ a });
  const message = useCallback(() => {
    console.log("rerendering has happened!");
    return [a   "SAMSUNG", a   "MOTO", a   "NOKIA"];
  }, [a]);

  const val = useMemo(() => message(), [message]);

  return (
    <div className="App">
      <input value={a} onChange={(e) => seta(e.target.value)} />
      <button
        onClick={() =>
          Color === "#12ab34" ? setColor("#abb111") : setColor("#12ab34")
        }
      >
        toggle
      </button>
      <List message={val} Color={Color} />
    </div>
  );
}

export default App;

Link

That being said, the above approach is still counter intuitive to me. The purpose of your function is to calculate a value,. And in your <List... statement, you simple call the function to get the value. So basically you do not need the function anywhere, and just the value. Using useMemo will do the job here.

import { useState, useCallback, useMemo } from "react";
import List from "./List";

function App() {
  const [a, seta] = useState("");
  const [Color, setColor] = useState("#12ab34");
  console.log({ a });
  const message = useMemo(() => {
    console.log("rerendering has happened!");
    return [a   "SAMSUNG", a   "MOTO", a   "NOKIA"];
  }, [a]);

  return (
    <div className="App">
      <input value={a} onChange={(e) => seta(e.target.value)} />
      <button
        onClick={() =>
          Color === "#12ab34" ? setColor("#abb111") : setColor("#12ab34")
        }
      >
        toggle
      </button>
      <List message={message} Color={Color} />
    </div>
  );
}

export default App;

Link

CodePudding user response:

When you use UseCallback the function will be called on each render the difference is a memorized version of it will be called (new instance will NOT be created). It is useful when you're passing functions as props.

In your case, you should consider using UseMemo instead which returns a memorized value.

  • Related