Home > Software design >  React useEffect to have different behavior on first load and subsequent updates
React useEffect to have different behavior on first load and subsequent updates

Time:04-06

I am using React with typescript and I want to convert my class component to a functional component, but my class component has two different componentDidMount and comonentDidUpdate behaviors:

    componentDidMount() {
        this.props.turnResetOff();
    }
    componentDidUpdate() {
        if (this.props.resetForm) {
            this.resetChangeForm();
            this.props.turnResetOff();
        }
    }

I just want my form to reset every time it loads except the first time, because I have a menu drop-down that allows clearing the form but I want the data to not reset on mount.

I tried using this: componentDidMount equivalent on a React function/Hooks component?

    const turnResetOff = props.turnResetOff;// a function
    const resetForm = props.resetForm;
    const setPersonId = props.setPersonId;// a function
    useEffect(() => {
        turnResetOff();
    }, [turnResetOff]);

    useEffect(() => {
        const resetChangeForm = () => {/*definition*/};

        if (resetForm) {
            resetChangeForm();
            turnResetOff();
        }
    }, [resetForm, turnResetOff, setPersonId]);

However, this causes an infinite re-render. Even if I useCallback for turnResetOff:

   turnResetOff={useCallback(() => {
        if (shouldReset) {
            setShouldReset(false);
        }
    }, [shouldReset])}

I also tried using useRef to count the number of times this has been rendered, with the same result (infinite rerender - this is a simplified version even).

    const [shouldReset, setShouldReset] = useState<boolean>(false);
    const mountedTrackerRef = useRef(false);

    useEffect(() => {
        if (mountedTrackerRef.current === false) {
            console.log("mounted now!");
            mountedTrackerRef.current = true;
            // props.turnResetOff();
            setShouldReset(false);
        } else {
            console.log("mounted already... updating");
            // if (props.resetForm) {
            if (shouldReset) {
                // resetChangeForm();
                // props.turnResetOff();
                setShouldReset(false);
            }
        }
    }, [mountedTrackerRef, shouldReset]);

CodePudding user response:

When you call useEffect() you can return a clean-up function. That cleanup function gets called when the component is unmounted. So, perhaps what you want to do is this: when you are called with turnResetOff then call it, and return a function that calls turnResetOff. The return function will be called when the component unmounts, so next time the component mounts it won't reset.

Something to along these lines:

useEffect(
  () => {
    turnResetOff()
    return () => {setShouldReset(false)}
  }
,[turnResetOff, setShouldReset])

CodePudding user response:

Using the logic you have in the class component, the fellowing should give you identical behavior in a functional component

const turnResetOff = props.turnResetOff;// a function
const resetForm = props.resetForm;
const setPersonId = props.setPersonId;// a function

// useEffect with an empty dependency array is identical to ComponentDidMount event
useEffect(() => {
    turnResetOff();
}, []);
// Just need resetForm as dependency since only resetForm was checked in the componentDidUpdate
useEffect(() => {
    const resetChangeForm = () => {/*definition*/};

    if (resetForm) {
        resetChangeForm();
        turnResetOff();
    }
}, [resetForm]);
  • Related