<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

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.