In my experience, it's not typical to pass un-memoized functions down via props like this.
// don't do this
<Wrapper
getWebsites={() => fetchJson('websites').then(setWebsites)}
loadUserRatings={() => fetchJson('ratings').then(setUserRatings)}
/>
If they are correctly memoized (using a hook like useCallback(), or by being defined outside of any component), then it's safe to pass them to the deps of your useEffect() without any difference in behavior. Here's an example that fixes the scenario above.*
// do this
const fetchJson = (...args) => fetch(...args).then(res => res.json());
const Parent = () => {
const [websites, setWebsites] = useState([]);
const [userRatings, setUserRatings] = useState({});
// useCallback creates a memoized reference
const getWebsites = useCallback(
() => fetchJson('websites').then(setWebsites),
[setWebsites]
);
const loadUserRatings = useCallback(
() => fetchJson('ratings').then(setUserRatings),
[setUserRatings]
);
...
<Wrapper
getWebsites={getWebsites}
loadUserRatings={loadUserRatings}
/>
* useState() memoizes the dispatch function in its return value, so technically it would be safe to pass [] as the deps to each useCallback() here, but I believe that specifying the dispatch functions as dependencies helps improve clarity by explicitly communicating the author's intent, and there's no disadvantage to passing them.
Ramesh's answer is sufficient for this situation.
If you find that you're stuck with the first scenario, then, as a last resort, you can initialize props into your component's state like this.
const Wrapper = (props) => {
const [{ getWebsites, loadUserRatings }] = useState(props);
useEffect(() => {
getWebsites();
loadUserRatings();
}, [getWebsites, loadUserRatings]);
return (
<>
<Header />
<Websites />
<Sync />
</>
);
};