用于获取数据的自定义 React 钩子无法正常工作

Posted

技术标签:

【中文标题】用于获取数据的自定义 React 钩子无法正常工作【英文标题】:Custom React hook for fetching data is not working correct 【发布时间】:2022-01-01 18:08:19 【问题描述】:

我有这个用于从 API 获取数据的自定义 React 钩子:

import  useState, useEffect  from 'react';

const API_CHARACTERS = 'https://rickandmortyapi.com/api/character';

export const useFetchData = () => 
  const [data, setData] = useState();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => 
    setLoading(true);

    fetch(API_CHARACTERS)
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch(() => setError('Data fetching is failed!'))
      .finally(() => setLoading(false));
  , [])

  return  data, loading, error 

为了与正在获取的数据进行交互,我有这个组件

import React from 'react';
import './app.css';

import  useFetchData  from './hooks/useFetch';

function App() 
  const  data, loading, error  = useFetchData();
  console.log(data)


  return (
    <div className="App">
    </div>
  )


export default App;

当我试图处理 data 变量时 - 一切都很好。但是当我试图获得类似 data.results 的东西时,我会在下次刷新页面后得到这个: error image

【问题讨论】:

【参考方案1】:

完成异步任务(AJAX 调用)需要一些时间。您可以使用 useEffect 和依赖数组来检查数据是否可用。

const API_CHARACTERS = "https://jsonplaceholder.typicode.com/users";

const useFetchData = () => 
  const [data, setData] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  React.useEffect(() => 
    setLoading(true);
    fetch(API_CHARACTERS)
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch(() => setError("Data fetching is failed!"))
      .finally(() => setLoading(false));
  , []);

  return  data, loading, error ;
;

const App = () => 
  const  data, loading, error  = useFetchData();
  

 React.useEffect(() => 
    console.log(data); // called once data will change
  , [data]);

  if (loading) 
    return <div className="App">Loading... </div>;
  

  if (error) 
    return <div className="App">JSON.stringify(error)</div>;
  

  return (
    <div className="App">
      data?.map((item) => 
        return <div key=item.id>item.name</div>;
      )
    </div>
  );
;

ReactDOM.render(<App />, document.getElementById("root"));
<script
  crossorigin
  src="https://unpkg.com/react@17/umd/react.production.min.js"
></script>
<script
  crossorigin
  src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"
></script>
<div id="root"></div>

useEffect 的Dependencies 参数是useEffect(callback, dependencies)

让我们探索副作用和运行:

未提供:每次渲染后都会运行副作用。

 import  useEffect  from 'react';
    
    function MyComponent() 
      useEffect(() => 
        // Runs after EVERY rendering
      );  
    

一个空数组[]:副作用在初始渲染后运行一次。

 import  useEffect  from 'react';
    
    function MyComponent() 
      useEffect(() => 
        // Runs ONCE after initial rendering
      , []);
    

有 props 或 state 值[prop1, prop2, ..., state1, state2]:只有在任何依赖值发生变化时才会产生副作用。

import  useEffect, useState  from 'react';

function MyComponent( prop ) 
  const [state, setState] = useState('');
  useEffect(() => 
    // Runs ONCE after initial rendering
    // and after every rendering ONLY IF `prop` or `state` changes
  , [prop, state]);

【讨论】:

【参考方案2】:

因为api call 需要一些时间,所以您的控制台不会立即打印。可以使用useEffect钩子查看数据:

useEffect(() => 
    if (data) 
      console.log(data.results, "result");
    
  , [data]);

【讨论】:

以上是关于用于获取数据的自定义 React 钩子无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

反应:带有自定义钩子的滑块无法正常工作

为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?

获取更多功能未定义用于 useLazyQuery react-apollo 钩子

React中传递道具和映射数据

如何将 React 组件的自定义钩子与“map”一起使用

如何使用 react-hooks-testing-library 测试自定义 async/await 钩子