简体   繁体   中英

React hook - `useEffect` with clean up

I'm learning React Hook and useEffect but I might not get the key point of using it correctly.

I have a following scenario:

  1. If a user switches the dropdown, will check if a flag of isAnyChange from the global state if there is any update on the current page.
  2. If there is no change, will go ahead and redirect to next page,
  3. If there is any change, will display a confirm dialog.

Then inside the confirm dialog, will have 2 buttons:

  • 4.1 one asks for saving, checking the validation and redirect,
  • 4.2 one asks for do not save and redirect.

I am including the above logic with using different useEffect , but I am not sure if I am doing the correct way since it looks wired to myself and making things complicated, what'd be the best way to decomposite my functionality then? am I doing the correct design here by using those local state flag to trigger different useEffect ? I couldn't think of any better way though...

const pageComponent = props => {
   const [isSelectChange, setIsSelectChange] = useState(false);
   const [canRedirect, setCanRedirect] = useState(false);
   const [isSaveCompleted, setIsSaveCompleted] = useState(false);

   const anyChange = useSelector(state => return state.anyChange;);
   const anyValidError = useSelector(state => return state.anyValidError;);

   // step 1. dropdown change to change local state and trigger useEffect in step 2
   const selectChange = () => {
      setIsSelectChange(true);
   }

   // step 2. state isSelectChange to trigger step 3 howConfirmDialog or useEffect in step 6
   useEffect(() => {
     if (isSelectChange) {
        if (anyChange) { showConfirmDialog(); }
        else { setCanRedirect(); }
        // should I placed it here? but this seems to trigger the same useEffect a second time even though no code is executing 
        // setIsSelectChange(false);
     }

     return () {
        // clean up to reset the flag back to avoid looping here on isSelectChange, is it the right place to do it here?
        setIsSelectChange(false);
     }
   }, [isSelectChange])

   // step 3. dispatch a confirm dialog
   const showConfirmDialog() => {
      dispatch(openConfirmDialog(
        dialog: <ConfirmDialog confirmhdlr={saveAndRedirect} cancelhdlr={cancelAndRedirect} />
      );
   }

   // step 4.1 save and redirect
   const saveAndRedirect = async () => {
      await(savePage());
      // this is to trigger another useEffect monitoring on isSaveCompleted flag
      setIsSaveCompleted(true);
      setCanRedirect(true);
   }
   
   // step 4.2 cancel and redirect
   const cancelAndRedirect = () => {
      setCanRedirect(true);
   }
   
   // step 5. state isSaveCompleted to trigger
   useEffect(() => {
     if (isSaveCompleted && !anyValidError) {
        // this is to trigger another useEffect monitoring on "canRedirect"
        setCanRedirect(true);
        // should I placed it here? but this seems to trigger the same useEffect a second time even though no code is executing 
        // setIsSaveCompleted(false);
     }

     return () {
        // clean up to reset the flag back to avoid looping here on isSaveCompleted flag, is it the right place to do it here?
        setIsSaveCompleted(false);
     }
   }, [isSaveCompleted])

   // step 6. state canRedirect to trigger redirect
   useEffect(() => {
     if (canRedirect) {
       if (isSaveCompleted && !anyValidError) {
          // this is to trigger another useEffect monitoring on "canRedirect"
          setCanRedirect(true);
       }
       // should I placed it here? but this seems to trigger the same useEffect a second time even though no code is executing 
       // setCanRedirect(false);
     }

     return () {
        // clean up to reset the flag back to avoid looping here on canRedirect flag, is it the right place to do it here?
        setCanRedirect(false);
     }
   }, [canRedirect])

   return (<select onChange={selectChange}>)
}

as you see I have different flags to trigger different useEffect , I could do all of them in one function, then why would use useEffect here?

It is not an answer but it should help you to understand hook a bit better. You ve got three useEffects and each of them works every time when ANY state is changed. So your step 1 fires all useEffects below. Use dependencies list like this:

useEffect(()=>{
  ...
}, [isSelectChange]) // this hook fires only when isSelectChange state changes.

useEffect(()=>{
  ...
}, []) // this hook fires only once, when the component ie rendering for the very first time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM