Search code examples
react-reduxreact-hooksuse-effectuse-state

React custom hook useState initialization value not update through outside props


I have a custom hook that has a locale state value by using useState, and I set the initial value from outside props, but when my props changes, my internal state value didn't get updated, in addition I am not quite understanding that, how many instance of custom hook in my component or application lifecycle where each time it's been triggered?

Here is the code example:

// custom hook
const useCustomHook = (initValue) => {
   const [isFetching, setIsFetching] = useState(initValue);

   useEffect(() => {
      console.log('initValue :>> ', initValue, ', isFetching :>>', isFetching);
   }, [initValue, isFetching);
}
// component
const myComponent = (props) => {
   const [shouldTrigger, setShouldTrigger] = useState(false);

   useCustomHook(shouldTrigger);

   onButtonClick = () => {
     setShouldTrigger(true);
   }
}

Here are the console logs that I get,

// when my component mouts
'initValue :>> ', false, ', isFetching :>>', false
// when button clicked
'initValue :>> ', true, ', isFetching :>>', false

as you can see, as long as I set my shouldTrigger to true from the main component, my custom hook gets invoked, however, the local state value isFetching inside my custom hook value is still false, shouldn't it be true as it'll be assigned from outside props every time? and is my above two useCustomHook the same instance or different? If there are different instance being called, why the second instance not set initial value as "true"?

Here is the code link https://stackblitz.com/edit/react-yma5my?file=index.js


Solution

    1. I'm not sure but I think it's because if you use useState you can define this value only once.
    2. and is my above two useCustomHook the same instance or different they will be different.

    You can rewrite your code to

    // custom hook
    const useCustomHook = (initValue) => {
       const [isFetching, setIsFetching] = useState(initValue);
    
       useEffect(() => {
          console.log('initValue :>> ', initValue, ', isFetching :>>', isFetching);
       }, [initValue, isFetching);
      return [isFetching, setIsFetching]
    }
    // component
    const myComponent = (props) => {
       const [isFetching, setIsFetching] = useCustomHook(false);
    
       onButtonClick = () => {
         setIsFetching(true);
       }
    }
    

    UPDATE

    I just got an idea how to write in style that you wanted from start, but my first suggestion still better(as i think)

    // custom hook
    const useCustomHook = (value) => {
       const [isFetching, setIsFetching] = useState(value);
    
       useEffect(() => {
         setIsFetching(value);
       }, [value]);
    
       useEffect(() => {
          console.log('value :>> ', value, ', isFetching :>>', isFetching);
       }, [initValue, isFetching);
    }
    // component
    const myComponent = (props) => {
       const [shouldTrigger, setShouldTrigger] = useState(false);
    
       useCustomHook(shouldTrigger);
    
       onButtonClick = () => {
         setShouldTrigger(true);
       }
    }
    

    It cause additional calling of setState but implements updating of state based on input props;