In this article, I’m going to discuss the use of useCallback, useMemo, useRef, and useReducer hook.
useCallback hook: It memorizes a callback function. So new instances of that function are not created. And it will only forget it when the dependency value is changed.
import React, { useCallback, useState } from "react";
import "./App.css";
import Title from "./components/Title/Title";
function App() {
const [increase1, setIncrease1] = useState(0);
const [increase5, setIncrease5] = useState(0);
const handleIncrease1 = useCallback(() => {
console.log("inside 1");
setIncrease1(increase1 + 1);
}, [increase1]);
const handleIncrease5 = useCallback(() => {
console.log("inside 5");
setIncrease5(increase5 + 5);
}, [increase5]);
return (
<div className="App">
<Title />
{/* increase value by 1 */}
<h4>Increase value by 1</h4>
<p>{increase1}</p>
<button onClick={handleIncrease1}> Increase by 1</button>
{/* increase value by 5 */}
<h4>Increase value by 5</h4>
<p>{increase5}</p>
<button onClick={handleIncrease5}> Increase by 5</button>
</div>
);
}
export default App;
UseMemo hooks: It’s a little different from useCallback hook. useCallback memorizes the whole function but it memorizes only the return value of a function. And it forgets that when the dependency value is changed.
import React, { useCallback, useMemo, useState } from "react";
import "./App.css";
import Title from "./components/Title/Title";
function App() {
const [increase1, setIncrease1] = useState(0);
const [increase5, setIncrease5] = useState(0);
const handleIncrease1 = useCallback(() => {
console.log("inside 1");
setIncrease1(increase1 + 1);
}, [increase1]);
const handleIncrease5 = useCallback(() => {
console.log("inside 5");
setIncrease5(increase5 + 5);
}, [increase5]);
const isEvenOrOdd = useMemo(() => {
let i = 0;
while (i < 1000000000) i++;
return increase1 % 2 === 0;
}, [increase1]);
return (
<div className="App">
<Title />
{/* increase value by 1 */}
<h4>Increase value by 1</h4>
<p>{increase1}</p>
<p>{isEvenOrOdd ? "Even" : "Odd"}</p>
<button onClick={handleIncrease1}> Increase by 1</button>
{/* increase value by 5 */}
<h4>Increase value by 5</h4>
<p>{increase5}</p>
<button onClick={handleIncrease5}> Increase by 5</button>
</div>
);
}
export default App;
useRef: If we want to get a element or its value then we use document.getElementById or document.getElementsByClassName etc. You can use them on react but it is not a good practice. To solve this react give us useRef hook. You just have to say which node element you want to reference. Then it will return the referenced node in the referenced variable.current
import React, { useEffect, useRef } from "react";
const Form = () => {
const inputRef = useRef();
useEffect(() => {
console.log(inputRef.current.value);
}, []);
return (
<div>
<input ref={inputRef} />
</div>
);
};
export default Form;
If you have to use ref to a child component then you have to use forward ref to pass ref from parent to child component
Parent component where the ref is located
import React, { useEffect, useRef } from "react";
import "./App.css";
import Input from "./components/Input";
function App() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
});
return (
<div className="App">
<Input placeholder="Enter your name" ref={inputRef} type="text" />
</div>
);
}
export default App;
Child component where I want to use the ref
import React from "react";
const Input = ({ type, placeholder }, ref) => {
return <input ref={ref} type={type} placeholder={placeholder} />;
};
const forwardedInput = React.forwardRef(Input);
export default forwardedInput;
Here’s a little trick of using useRef. When you want to use a function which is scoped inside the useEffect hook.
import React, { useEffect, useRef, useState } from "react";
const Clock = () => {
const [date, setDate] = useState(new Date());
const intervalRef = useRef();
const tick = () => {
setDate(new Date());
};
useEffect(() => {
intervalRef.current = setInterval(tick, 1000);
// do the cleanup stop the timer
return () => {
clearInterval(intervalRef.current);
};
}, []);
return (
<div>
<p>Time: {date.toLocaleTimeString()}</p>
<p>
<button onClick={() => clearInterval(intervalRef.current)}>Stop</button>
</p>
</div>
);
};
export default Clock;
useReducer: useReducer is like the Array.prototype.reduce method in vanilla JS. The difference is that reduce method takes a reducer function and initialValue but useReducer takes the reducer function and initialState as the second parameter. Reduce method returns a single value but useReducer returns a tuple [newState, dispatch]
import React, { useReducer } from "react";
import "./App.css";
const initialState = 0;
const reducer = (state, action) => {
switch (action) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return state;
}
};
function App() {
const [count, dispatch] = useReducer(reducer, initialState);
return (
<div className="App">
<p>{count}</p>
<button onClick={() => dispatch("increment")}>Increase</button>
<button onClick={() => dispatch("decrement")}>Decrease</button>
</div>
);
}
export default App;
You can use useReducer in a complex situation where you have different as for example counters and they have a different functions to update their value.
import React, { useReducer } from "react";
const initialState = {
counter: 0,
counter2: 0,
};
const reducer = (state, action) => {
/* you have to merge object immutably to do that use the spread operator */
switch (action.type) {
case "increment":
return { ...state, counter: state.counter + action.value };
case "decrement":
return { ...state, counter: state.counter - action.value };
case "increment2":
return { ...state, counter2: state.counter2 + action.value };
case "decrement2":
return { ...state, counter2: state.counter2 - action.value };
default:
return state;
}
};
/* you have to merge state immutably */
function Counter() {
const [count, dispatch] = useReducer(reducer, initialState);
return (
<React.Fragment>
{/* counter 1 */}
<div>
<p>Counter1: {count.counter}</p>
<button
onClick={() =>
dispatch({
type: "increment",
value: 1,
})
}
>
Increment by 1
</button>
<button
onClick={() =>
dispatch({
type: "decrement",
value: 1,
})
}
>
Decrement by 1
</button>
</div>
{/* counter 2 */}
<div>
<p>Counter2: {count.counter2}</p>
<button
onClick={() =>
dispatch({
type: "increment2",
value: 1,
})
}
>
Increment2 by 1
</button>
<button
onClick={() =>
dispatch({
type: "decrement2",
value: 1,
})
}
>
Decrement2 by 1
</button>
</div>
</React.Fragment>
);
}
export default Counter;
Top comments (0)