import React from "react";
function App() {
console.log("App: render start");
const [showChild, setShowChild] = React.useState(() => {
console.log("App: useState(() => false)");
return false;
});
console.log(`App: showChild = ${showChild}`);
React.useEffect(() => {
console.log("App: useEffect(() => {})");
return () => {
console.log("App: useEffect(() => {}) cleanup");
};
});
React.useEffect(() => {
console.log("App: useEffect(() => {}, [])");
return () => {
console.log("App: useEffect(() => {}, []) cleanup");
};
}, []);
React.useEffect(() => {
console.log("App: useEffect(() => {}, [showChild])");
return () => {
console.log("App: useEffect(() => {}, [showChild]) cleanup");
};
}, [showChild]);
const element = (
<>
<label>
<input
type="checkbox"
checked={showChild}
onChange={(e) => setShowChild(e.target.checked)}
/>{" "}
Show child
</label>
<div
style={{
padding: 10,
margin: 10,
height: 30,
width: 30,
border: "solid"
}}
>
{showChild ? <Child /> : null}
</div>
</>
);
console.log("App: render end");
return element;
}
function Child() {
console.log(" Child: render start");
const [count, setCount] = React.useState(() => {
console.log(" Child: useState(() => 0)");
return 0;
});
console.log(` Child: count = ${count}`);
React.useEffect(() => {
console.log(" Child: useEffect(() => {})");
return () => {
console.log(" Child: useEffect(() => {}) cleanup");
};
});
React.useEffect(() => {
console.log(" Child: useEffect(() => {}, [])");
return () => {
console.log(" Child: useEffect(() => {}, []) cleanup");
};
}, []);
React.useEffect(() => {
console.log(" Child: useEffect(() => {}, [count])");
return () => {
console.log(" Child: useEffect(() => {}, [count]) cleanup");
};
}, [count]);
const element = (
<button onClick={() => setCount((previousCount) => previousCount + 1)}>
{count}
</button>
);
console.log(" Child: render end");
return element;
}
ReactDOM.render(<App />, document.getElementById("root"));
You can find the live code at https://codepen.io/Yemisrach15/pen/YzgxpRO?editors=0011.
Ignoring the console logs, let’s go over what the code snippet does. The root or main entry point is App
. This component renders a checkbox input with a label and Child
component based on a condition. The Child
component renders a button that increments a count state when clicked. Both components maintain some state, in the case of App
whether to show child or not, showChild
, and in the case of Child
the number of times the button is clicked, count
. They each also have three useEffect
s, one without dependency, one with empty dependency, one with one dependency.
From the behavior of useEffect
s, you may know that the callback function passed to each executes
- on every render when there is no dependency
- only on initial render when there is an empty dependency array
- on initial render and on a dependency change when there is a non-empty dependency array
Also notice that each useEffect
has a cleanup function which runs when the component unmounts.
Hoping everything is clear by now, let’s jump straight into the hooks flow. We will first take a look at what happens on initial load.