useEffect
can be used to run the code once but this happens on component mount, so it's a counterpart to componentDidMount
, not a constructor:
let components = useRef();
useEffect(() => {
components.current = props.components.map(createComponentFactory(props.context))
}, []);
// components.current === null
// on first render
useMemo
can be used to run the code once on first render:
const components = useMemo(
() => props.components.map(createComponentFactory(props.context)),
[]
);
It isn't guaranteed to run the code once in future React versions:
You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.
useState
can be used to run the code once on first render, too:
const [components] = useState(
() => props.components.map(createComponentFactory(props.context))
);
Due to limitations of other options, the last option can be considered a preferable way to do this.