Reactjs 为什么自定义钩子会返回两次结果

Reactjs 为什么自定义钩子会返回两次结果,reactjs,react-hooks,Reactjs,React Hooks,下面的文章是关于创建一个用于获取数据的自定义钩子的,这很简单 但有一部分我不知道它是如何工作的 为什么这个钩子会返回两次结果?(isLoading=true isLoading=false) 函数useAPI(方法,…参数){ //----国家 const[data,setData]=useState(null); const[isLoading,setIsLoading]=useState(false); const[error,setError]=useState(null); //---

下面的文章是关于创建一个用于获取数据的自定义钩子的,这很简单

但有一部分我不知道它是如何工作的

为什么这个钩子会返回两次结果?(isLoading=true isLoading=false)

函数useAPI(方法,…参数){
//----国家
const[data,setData]=useState(null);
const[isLoading,setIsLoading]=useState(false);
const[error,setError]=useState(null);
//----API
const fetchData=async()=>{
onError(空);
试一试{
设置加载(真);
setData(等待APIService[method](…params));
}捕获(e){
设置错误(e);
}最后{
设置加载(假);
}
};
useffect(()=>{fetchData()},[]);
返回[data,isLoading,error,fetchData];
}
功能主屏幕(){
const[users,isLoading,error,retry]=useAPI('loadUsers');
//---显示错误
如果(错误){
返回
}
//---模板
返回(
{
(users&&users.length>0)&&
}
)

您的
最后
块在
尝试
块后启动

请注意,无论是否引发异常,finally块都会执行


事件处理程序和生命周期方法中反应批处理状态更新

fetchData
不是其中任何一个,因此不会发生批处理

现在,当调用
fetchData()
时:

成功时,会出现
3
异步事件,我们只对
#1
#3

  • 将加载状态从默认值设置为
    true
  • #1
    async
    setState
    将加载状态设置为
    false
旁注:乍一看,这个钩子有缺陷,
fetchData
在每次渲染时都会被重新分配,您将收到缺少依赖项的警告


你预计会发生什么?所以所有状态更新都会被返回,除非它是事件处理程序或生命周期方法。好吧,我猜状态更新会被返回。是否有文档链接。我知道每个人都希望它像这样工作,但作为一个新手,我感到惊讶。这是一个内部实现,所以你应该如果我不考虑它,你可以阅读更多。好的thx,那么如果我将逻辑移出fetchdata,更新将被批处理,整个事情将被破坏,我会尝试。这不是我提到的旁注的解决方案,如何修复它超出了当前问题的范围。是的,我不是指旁注,而是指我的理解批处理与非批处理行为的比较。
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>
  )
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);
  }
};