I have a custom hook that keeps a list of toggle states and while I'm seeing the internal state aligning with my expectations, I'm wondering why a component that listens to changes on the state kept by this hook isn't re-rendering on change. The code is as follows
const useToggle = () => {
const reducer = (state, action) => ({...state, ...action});
const [toggled, dispatch] = useReducer(reducer, {});
const setToggle = i => {
let newVal;
if (toggled[i] == null) {
newVal = true;
} else {
newVal = !toggled[i];
}
dispatch({...toggled, [i]: newVal});
console.log('updated toggled state ...', toggled);
};
return {toggled, setToggle};
};
const Boxes = () => {
const {setToggle} = useToggle()
return Array.from({length: 8}, el => null).map((el,i) =>
<input type="checkbox" onClick={() => setToggle(i)}/>)
}
function App() {
const {toggled} = useToggle()
const memoized = useMemo(() => toggled, [toggled])
useEffect(() => {
console.log('toggled state is >>>', toggled) // am not seeing this on console after changes to toggled
}, [toggled])
return (
<div className="App">
<Boxes />
</div>
);
}
Turns out, it doesn't really matter, whether the state change in hooks is “internal” or not. Every state change in a hook, whether it affects its return value or not, will cause the “host” component to re-render.
Inside, useEffect compares the two objects, and since they have a different reference, it once again fetches the users and sets the new user object to the state. The state updates then triggers a re-render in the component.
What is the React UseEffect? The useEffect hook has superpowers that enable us to design our custom hooks. When a change occurs, it allows us to perform side effects in functional components. It allows data retrieval, DOM modification, and function execution each time a component renders.
You can add the state variables you want to track to the hook's dependencies array and the logic in your useEffect hook will run every time the state variables change. Copied! import {useEffect, useState} from 'react'; const App = () => { const [count, setCount] = useState(0); useEffect(() => { console.
Sorry, something went wrong. exactly as @malerba118 said, state hooks will not rerender if you pass the same value/object to it. React encourages an immutable approach to ensure consistency, especially between renders. I'd go further and rewrite your handler to -
When ever the state is changed it should re render the componenet . In my case it is not re rendering component. When ever a component is re rendered this.fetchQuote inside ComponetDidMount should be called.
Removing the hook or the component itself means it's not fetched in that screen anymore. State (what's cached), behaviour (which effects load and invalidate the data) and UI can be closely linked together again, so they evolve organically together with your app.
To be honest, no. I’m not even sure that it’s true , I just seem to remember reading about it (although I might be getting confused with conditional rendering / the shouldComponentUpdate hook ). I know you can specify something not to render. As I said, I’m still learning myself, so hopefully someone who knows React well can explain it for us
It's because you are using useToggle
twice.
App
Boxes
.When you dispatch the action in Boxes
, it's updating the toggled
instance for Boxes
(which is not retrieved in it).
Think of your custom hook like how you use useState
. When you use useState
, each component gets its own state. Same goes for the custom hook.
So there are a few ways you can address the issue.
setToggle
from App
to Boxes
via prop-drilling setToggle
instance in the App
component down)Here is an example of prop-drilling.
You can follow along
const Boxes = ({ setToggle }) => {
// const { setToggle } = useToggle();
return Array.from({ length: 8 }, el => null).map((el, i) => (
<input key={i} type="checkbox" onClick={() => setToggle(i)} />
));
};
function App() {
const { toggled, setToggle } = useToggle();
useEffect(() => {
console.log("toggled state is >>>", toggled); // am not seeing this on console after changes to toggled
}, [toggled]);
return (
<div className="App">
<Boxes setToggle={setToggle} />
</div>
);
}
Note: that I added key
props in Boxes
using the index i
(and it is a bad practice by the way)
You can see that it's now working as you'd expect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With