2

The post below is about creating a custom hook for fetching data, and it's straightforward.

https://dev.to/patrixr/react-writing-a-custom-api-hook-l16

There is one part though that I don't see how it works.

Why would this hook return results twice? (isLoading=true isLoading=false)

function useAPI(method, ...params) {
    // ---- State
    const [data, setData]           = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError]         = useState(null);

    // ---- API
    const fetchData = async () => {
      onError(null);
      try {
        setIsLoading(true);
        setData(await APIService[method](...params));
      } catch (e) {
        setError(e);
      } finally {
        setIsLoading(false);
      }
    };

    useEffect(() => { fetchData() }, []);

    return [ data, isLoading, error, fetchData ];
}


function HomeScreen() {
  const [ users, isLoading, error, retry ] = useAPI('loadUsers');

  // --- Display error
  if (error) {
    return <ErrorPopup msg={error.message} retryCb={retry}></ErrorPopup>
  }

  // --- Template
  return (
    <View>
      <LoadingSpinner loading={isLoading}></LoadingSpinner>
      {
          (users && users.length > 0) &&
            <UserList users={users}></UserList>
      }
    </View>
  )
Spiff
  • 3,873
  • 4
  • 25
  • 50

2 Answers2

2

React batches state updates in event handlers and lifecycle methods.

fetchData is not any of those, therefore no batching will occur.

Now, when calling fetchData():

const fetchData = async () => {
  onError(null);
  try {
    // #1 async setState
    setIsLoading(true);

    const data = await APIService[method](...params);

    // #2 async setState
    setData(data);

  } catch (e) {
    setError(e);
  } finally {

    // #3 async setState
    setIsLoading(false);
  }
};

On success, there are 3 async events, which we only interested in #1 and #3

  • Setting the loading state to true from the default value false
  • Setting the loading state to false from the #1 async setState.

Side Note: From first glance this hook has flaws, fetchData is re-assigned on every render and you will get missing dependencies warnings.

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • So all state updates wiĺl be returned unless its an event handlers or a lifecycle method. Ok i guessed that the state updates are returned. Is there a documentation link for this. I understand that everyone expects that it works like this, but as a newbie i was surprised. – Spiff Dec 31 '19 at 19:00
  • It's an internal implementation so you should not be considered about it, you can read more [here](https://stackoverflow.com/questions/33613728/what-happens-when-using-this-setstate-multiple-times-in-react-component). – Dennis Vash Dec 31 '19 at 19:02
  • Ok thx, so if i move the logic out of fetchdata the updates will be batched and the whole thing will break, i will try that. – Spiff Dec 31 '19 at 19:37
  • That's not the solution for the side note that I mentioned, how to fix it is out of the scope of the current question. – Dennis Vash Dec 31 '19 at 19:39
  • Yes i was no refering to the side note but to my understanding of the batching vs the not batching behaviour. – Spiff Dec 31 '19 at 19:46
0

Your finally block is firing after the try block.

Note that the finally-block executes regardless of whether an exception is thrown.

The finally block

skoller
  • 89
  • 4