admin管理员组

文章数量:1425777

I'm using multiple useEffect hooks to perform the ponentDidMount and ponentDidUpdate functionalities, however, looks like when ponent loads, all my useEffect fires initially...

const testComp = () => {
   const stateUserId = useSelector(state => { return state.userId; });
   const [userId, setUserId] = useState(stateUserId);
   const [active, setActive] = useState(false);
   const [accountId, setAccountId] = useState();
   
   useEffect(() => {
      console.log('ponent did mount...');
   }, [userId]);
   
   useEffect(() => {
      console.log('should trigger when userId changes...');
   }, [userId]);

   useEffect(() => {
      console.log('should trigger when active changes...');
   }, [active]);
   
   useEffect(() => {
      console.log('should trigger when accountId changes...');
   }, [accounted]);
  
   return (<div>...</div);
}

when my ponent mounts, I see all those console log there

ponent did mount...
should trigger when userId changes...
should trigger when active changes...
should trigger when accountId changes...

How could I only let my first useEffect fires, but the other three fires when the dependency changes only?

I'm using multiple useEffect hooks to perform the ponentDidMount and ponentDidUpdate functionalities, however, looks like when ponent loads, all my useEffect fires initially...

const testComp = () => {
   const stateUserId = useSelector(state => { return state.userId; });
   const [userId, setUserId] = useState(stateUserId);
   const [active, setActive] = useState(false);
   const [accountId, setAccountId] = useState();
   
   useEffect(() => {
      console.log('ponent did mount...');
   }, [userId]);
   
   useEffect(() => {
      console.log('should trigger when userId changes...');
   }, [userId]);

   useEffect(() => {
      console.log('should trigger when active changes...');
   }, [active]);
   
   useEffect(() => {
      console.log('should trigger when accountId changes...');
   }, [accounted]);
  
   return (<div>...</div);
}

when my ponent mounts, I see all those console log there

ponent did mount...
should trigger when userId changes...
should trigger when active changes...
should trigger when accountId changes...

How could I only let my first useEffect fires, but the other three fires when the dependency changes only?

Share Improve this question asked Aug 1, 2020 at 3:16 DrexDrex 3,87110 gold badges46 silver badges77 bronze badges 4
  • 1 useEffect will always execute at least on mount, no matter what you pass in the dependency array. You should create a custom hook like useUpdateEffect. This question shows how stackoverflow./questions/55075604/… – Rodrigo Amaral Commented Aug 1, 2020 at 3:23
  • @Rodrigi Amara, thanks for sharing the idea, I'm wondering if that is the case, why not perform in the same main ponent by using the useRef flag but using a custom hook? In addition, how could I call the custom hook from my main ponent? – Drex Commented Aug 1, 2020 at 3:30
  • 1 Custom hooks are just functions. You can create a folder just for hooks and import them into your ponents. Or you could use useRef inside your ponent (like the most voted answer) does in the question, but you won't be able to reuse this logic outside this ponent. BTW, it's in the FAQ reactjs/docs/… – Rodrigo Amaral Commented Aug 1, 2020 at 3:35
  • All effects run at least one time there are some ref tricks to skip some. – Ioannis Potouridis Commented Aug 1, 2020 at 3:55
Add a ment  | 

3 Answers 3

Reset to default 4

useEffect is not a direct replacement of ponentDidMount and ponentDidUpdate. Effect will run after each render, which is why you are seeing all those console logs. According to the React documentation, the second parameter of useEffect means

you can choose to fire them (effects) only when certain values have changed.

After the initial render, if the ponent is rendered again, only effects watch the corresponding value changes are triggered.

One way to achieve what you want is by creating additional variables to host initial values and do parisons in the useEffect when you need to.

const testComp = () => {
  const initUserId =  useSelector(state => { return state.userId; });
  const stateUserId = initUserId;
   const [userId, setUserId] = useState(stateUserId);
   
   useEffect(() => {
      console.log('ponent did mount...');
   }, [userId]);
   
   useEffect(() => {
      if (userId !== initUserId) {
        console.log('should trigger when userId changes...');
      }
      
   }, [userId]);
  
   return <div>...</div>
}

Any useEffect hook will always be fired at ponent mount and when some of the variables in its dependency array changes. If you want to perform an action just when the variable changes you must check the ining value first and do the required validations. Also your first useEffect must have an empty dependency array to fire it just when the ponent mounts, because as it is it will also be called when userId changes.

you can use custom useEffect:

const useCustomEffect = (func, deps) => {
    const didMount = useRef(false);

    useEffect(() => {
        if (didMount.current) func();
        else didMount.current = true;
    }, deps);
}

and use it in your ponent:


useCustomEffect(() => {
      console.log('trigger when userId changes...');
}, [userId]);

本文标签: javascriptReact Hookmultiple quotuseEffectquot fires at componentDidMountStack Overflow