We can solve this using Hooks:
First we'll need a timeout hook for the delay.
This one is inspired by Dan Abramov's useInterval hook (see Dan's blog post for an in depth explanation), the differences being:
reset
function allowing us to restart the timer at any timeimport { useEffect, useRef, useCallback } from 'react';_x000D_
_x000D_
const useTimeout = (callback, delay) => {_x000D_
// save id in a ref_x000D_
const timeoutId = useRef('');_x000D_
_x000D_
// save callback as a ref so we can update the timeout callback without resetting the clock_x000D_
const savedCallback = useRef();_x000D_
useEffect(_x000D_
() => {_x000D_
savedCallback.current = callback;_x000D_
},_x000D_
[callback],_x000D_
);_x000D_
_x000D_
// clear the timeout and start a new one, updating the timeoutId ref_x000D_
const reset = useCallback(_x000D_
() => {_x000D_
clearTimeout(timeoutId.current);_x000D_
_x000D_
const id = setTimeout(savedCallback.current, delay);_x000D_
timeoutId.current = id;_x000D_
},_x000D_
[delay],_x000D_
);_x000D_
_x000D_
useEffect(_x000D_
() => {_x000D_
if (delay !== null) {_x000D_
reset();_x000D_
_x000D_
return () => clearTimeout(timeoutId.current);_x000D_
}_x000D_
},_x000D_
[delay, reset],_x000D_
);_x000D_
_x000D_
return { reset };_x000D_
};
_x000D_
and now we need a hook which will capture previous children and use our useTimeout hook to swap in the new children after a delay
import { useState, useEffect } from 'react';_x000D_
_x000D_
const useDelayNextChildren = (children, delay) => {_x000D_
const [finalChildren, setFinalChildren] = useState(children);_x000D_
_x000D_
const { reset } = useTimeout(() => {_x000D_
setFinalChildren(children);_x000D_
}, delay);_x000D_
_x000D_
useEffect(_x000D_
() => {_x000D_
reset();_x000D_
},_x000D_
[reset, children],_x000D_
);_x000D_
_x000D_
return finalChildren || children || null;_x000D_
};
_x000D_
Note that the useTimeout callback will always have the latest children, so even if we attempt to render multiple different new children within the delay time, we'll always get the latest children once the timeout finally completes.
Now in your case, we want to also delay the initial render, so we make this change:
const useDelayNextChildren = (children, delay) => {_x000D_
const [finalChildren, setFinalChildren] = useState(null); // initial state set to null_x000D_
_x000D_
// ... stays the same_x000D_
_x000D_
return finalChildren || null; // remove children from return_x000D_
};
_x000D_
and using the above hook, your entire child component becomes
import React, { memo } from 'react';_x000D_
import { useDelayNextChildren } from 'hooks';_x000D_
_x000D_
const Child = ({ delay }) => useDelayNextChildren(_x000D_
<div>_x000D_
... Child JSX goes here_x000D_
... etc_x000D_
</div>_x000D_
, delay_x000D_
);_x000D_
_x000D_
export default memo(Child);
_x000D_
or if you prefer: ( dont say i havent given you enough code ;) )
const Child = ({ delay }) => {_x000D_
const render = <div>... Child JSX goes here ... etc</div>;_x000D_
_x000D_
return useDelayNextChildren(render, delay);_x000D_
};
_x000D_
which will work exactly the same in the Parent render function as in the accepted answer
...
except the delay will be the same on every subsequent render too,
AND we used hooks, so that stateful logic is reusable across any component
...
...
use hooks. :D