<div id='root' ></div>
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #1a1d1d;
padding: 20px;
font-size: 0.875rem;
}
button {
background-color: #4caf50;
color: white;
padding: 10px 15px;
margin: 5px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.container {
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-width: 30rem;
margin: auto;
}
.rerender-child-container {
padding: 10px;
border: solid 1px #ccc;
margin: 10px 0;
}
.test-components-container {
display: flex;
}
/* table css */
th, td {
text-align: left;
padding: 8px;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f4f4f4;
}
.card {
/* display: none; */
border: 1px solid #ddd;
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
background-color: white;
max-width: 20rem
}
.card-item {
border: 1px solid
}
.card-content-container {
display: grid;
grid-template-columns: auto auto;
gap: 16px;
}
.card-button-container {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.child-components {
display: flex;
gap: 10px;
justify-content: space-around;
}
.component-header {
margin: 0 0 12px 0;
font-weight: bold;
}
.child {
border: solid 1px #ddd;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
padding: 8px;
}
/* Responsive styling */
@media screen and (max-width: 600px) {
body {
padding: 5px;
}
.container {
width: 100%;
}
table {
display: none;
}
.card {
display: block;
}
}
import React, {
useState,
useRef,
useEffect,
useCallback,
memo
} from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const App = () => {
const [count, setCount] = useState(0);
// state variable to trigger dynamic useCallBack
const [triggerDynamicFunc, setTriggerDynamicFunc] = useState(false);
const clickHandler = () => {
setCount((prevCount) => prevCount + 1);
};
const memoizedClickHandler = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, [triggerDynamicFunc]);
return (
<div className="container">
<button
onClick={() => {
setCount(count + 1);
}}
>
Trigger Re-render
</button>
<button
onClick={() => {
setTriggerDynamicFunc(true);
}}
>
Update Memoized function
</button>
<h3>Children with no props</h3>
<div className="child-components">
<div className="child">
<p className="component-header">Memoized Component</p>
<MemoizedChild isMemo={true} />
</div>
<div className="child">
<p className="component-header">Regular Component</p>
<RegularChild />
</div>
</div>
<h3>Children with props</h3>
<DemoTable>
<TestComponentRow
isMemo={false}
isCallBack={false}
clickHandler={clickHandler}
/>
<TestComponentRow
isMemo={false}
isCallBack={true}
clickHandler={memoizedClickHandler}
/>
<MemoTestComponentRow
isMemo={true}
isCallBack={false}
clickHandler={clickHandler}
/>
<MemoTestComponentRow
isMemo={true}
isCallBack={true}
clickHandler={memoizedClickHandler}
/>
</DemoTable>
<div className="card-container">
<TestComponentCard
isMemo={false}
isCallBack={false}
clickHandler={clickHandler}
/>
<TestComponentCard
isMemo={false}
isCallBack={true}
clickHandler={memoizedClickHandler}
/>
<MemoTestComponentCard
isMemo={true}
isCallBack={false}
clickHandler={clickHandler}
/>
<MemoTestComponentCard
isMemo={true}
isCallBack={true}
clickHandler={memoizedClickHandler}
/>
</div>
<hr />
</div>
);
};
const RegularChild = ({ isMemo = false }) => {
const renderCount = useRef(0);
if (isMemo) {
console.log("Memo Child re-rendered at ", new Date().toLocaleTimeString());
}
useEffect(() => {
renderCount.current += 1;
});
return <div>Render Count: {renderCount.current}</div>;
};
const MemoizedChild = memo(RegularChild);
const TestComponentRow = ({
clickHandler,
isMemo = false,
isCallBack
}) => {
// Component for testing click handlers
const renderCount = useRef(0);
const lastClickHandler = useRef(clickHandler);
let clickHandlerChanged = false;
if (clickHandler !== lastClickHandler.current) {
clickHandlerChanged = true;
lastClickHandler.current = clickHandler;
}
useEffect(() => {
renderCount.current += 1;
});
return (
<tr>
<td>{isMemo ? "yes" : "no"}</td>
<td>{isCallBack ? "useCallBack" : "inline"}</td>
<td>{renderCount.current}</td>
<td>
<button onClick={clickHandler}>update parent</button>
</td>
<td>{clickHandlerChanged ? "yes" : "no"}</td>
</tr>
);
};
const MemoTestComponentRow = memo(TestComponentRow);
const TestComponentCard = ({
clickHandler,
isMemo = false,
isCallBack
}) => {
// Component for testing click handlers
const renderCount = useRef(0);
const lastClickHandler = useRef(clickHandler);
let clickHandlerChanged = false;
if (clickHandler !== lastClickHandler.current) {
clickHandlerChanged = true;
lastClickHandler.current = clickHandler;
}
useEffect(() => {
renderCount.current += 1;
});
return (
<div className="card">
<div className="card-content">
<div className="card-content-container">
<div>
<strong>Is Memoized:</strong>
</div>
<div>{isMemo ? "Yes" : "No"}</div>
<div>
<strong>Handler Type:</strong>
</div>
<div>{isCallBack ? "useCallBack" : "inline"}</div>
<div>
{" "}
<strong>Renders:</strong>
</div>
<div>{renderCount.current}</div>
<div>
{" "}
<strong>Function Changed:</strong>
</div>
<div>{clickHandlerChanged ? "Yes" : "No"}</div>
</div>
<div className="card-button-container">
<button className="card-button" onClick={clickHandler}>
Update Parent
</button>
</div>
</div>
</div>
);
};
const MemoTestComponentCard = memo(TestComponentCard);
const DemoTable = ({ children }) => {
return (
<table>
<thead>
<tr>
<th>Memoized Component</th>
<th>Click Handler Type</th>
<th>Renders</th>
<th>Action</th>
<th>Function Changed</th>
</tr>
</thead>
<tbody>{children}</tbody>
</table>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.