Home > Blockchain >  Call React hook depending on Promise
Call React hook depending on Promise

Time:10-08

I have an ID stored in AsyncStorage and depending on this call, I want to make a server request.

So something like this is needed:

AsyncStorage.getID().then(id => {
   useLoadFromServer(id)
}

But I always struggle with getting errors about using hooks wrong. So far I tried:

// First Approach
const MyScreen = () => {
  const [ID, setID] = useState()

  AsyncStorage.getID()
    .then(id => setID(id))
    .catch(e => console.log(e))
  
  const { data } = useLoadRoot(ID) // Not the ID from AsyncStorage is used
}
//Second Approach
const MyScreen = async () => {
  const [ID, setID] = useState()

  const IDPromise = AsyncStorage.getID()
  const { data } = useLoadRoot(await IDPromise) // Possible Unhandled Promise Rejection

also I tried to use useEffect, which leads to React Hooks must be called in a React function component or a custom React Hook function

The useLoadRoot-hook just calls another hook UseLoadFromEndpoint doing the axios.get()

When trying to move the AsyncStorage-Request to the customHook, I get the same errors, as I call the useLoadFromEndpoint-hook incorrectly, but I have to / want to reuse the UseLoadFromEndpoint-Hook. How can I achive this?

CodePudding user response:

You can wrap it into another function and then check for the value with interval before calling the hook.

CodePudding user response:

The rules of hooks state that all hooks must run in the same order with each render cycle. This means we need to write conditional logic in a particular way. I would recommend this.

const MyScreen = () => {
  const [ID, setID] = useState()
  cosnt [data, setData] = useState()

  useEffect(() => {
    const getData = async () => {
      const id = await AsyncStorage.getID()
      setID(id)
      const { data } = useLoadRoot(id)
      setData(data)
    }
    getData()
  })
  
  if (data) {
    // do stuff
  }
  return null
}

CodePudding user response:

You need to either modify the useLoadRoot hook or wrap that logic in a child component. Hooks don't allow conditional usage.

Route 1: Rewrite useLoadRoot

const useLoadRoot = (id) => {
  const getRoot = async (rootId) => ...;
  const [root, setRoot] = useState();

  useEffect(() => {
    if (id != undefined) { 
       await getRoot(id);
    }
  }, [id]);

  return root;
}

This is just one way to achieve what you want. You can pass in an enabled property that is a boolean that allows requests only if true. This is the approach that is used in react-query, for example (see: docs).

Route 2: Conditional child component

const Parent = () => {
  const [ID, setID] = useState()

  AsyncStorage.getID()
    .then(id => setID(id))
    .catch(e => console.log(e))

  return ID ? <WithFetchRoot rootId={ID}/> : null; //could be a loader component instead of null
}

const WithFetchRoot = (id) => {
  const root = useLoadRoot(ID);

  ...
}

CodePudding user response:

It's because you have no return. All react components should return something so return null from your component and it should solve your problem. Also, to avoid unnecessary rendering, you should do it in useEffect with an empty array so it only get triggers once (after the component mounts).

  • Related