根据 Promise 调用 React hook

Call React hook depending on Promise

我在 AsyncStorage 中存储了一个 ID,根据这个调用,我想发出一个服务器请求。

所以需要这样的东西:

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

但我一直在努力解决有关错误使用钩子的错误。到目前为止我试过:

// 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

我也尝试使用 useEffect,这导致 React Hooks must be called in a React function component or a custom React Hook function

useLoadRoot-hook 只是调用另一个 hook UseLoadFromEndpointaxios.get()

当尝试将 AsyncStorage-Request 移动到 customHook 时,我遇到了同样的错误,因为我错误地调用了 useLoadFromEndpoint-hook,但我必须/想要重用 UseLoadFromEndpoint-Hook。我怎样才能做到这一点?

hooks 规则规定所有 hooks 必须 运行 在每个渲染周期中以相同的顺序。这意味着我们需要以特定方式编写条件逻辑。我会推荐这个。

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
}

那是因为你没有return。所有 React 组件都应该 return 从你的组件中得到 return null 这样的东西,它应该可以解决你的问题。此外,为避免不必要的渲染,您应该在 useEffect 中使用空数组进行渲染,这样它只会触发一次(在组件安装后)。

您需要修改 useLoadRoot 挂钩或将该逻辑包装在子组件中。挂钩不允许有条件地使用。

路线 1:重写 useLoadRoot

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

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

  return root;
}

这只是实现您想要的目标的一种方法。您可以传入一个 enabled 属性,它是一个布尔值,只有在为真时才允许请求。例如,这是在 react-query 中使用的方法(参见:docs)。

路线二:条件子组件

const Parent = () => {
  const [ID, setID] = useState()
  
  useEffect(() => {
    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);

  ...
}