对useEffect感到困惑

时间:2019-08-26 02:50:01

标签: javascript react-hooks use-effect

我正在构建我的第一个Custom React Hook,并对我认为代码的简单方面感到困惑:

export const useFetch = (url, options) => {
  const [data, setData] = useState();
  const [loading, setLoading] = useState(true);
  const { app } = useContext(AppContext);
  console.log('** Inside useFetch: options = ', options);

  useEffect(() => {
    console.log('**** Inside useEffect: options = ', options);
    const fetchData = async function() {
      try {
        setLoading(true);
        const response = await axios.get(url, options);
        if (response.status === 200) {
          setData(response.data);
        }
      } catch (error) {
        throw error;
      } finally {
        setLoading(false);
      }
    };
    fetchData();
  }, []);

  return { loading, data };
};

我将两个参数传递给useFetch:一个URL和一个headers对象,其中包含一个如下所示的AWS Cognito授权密钥:Authorization: eyJraWQiOiJVNW...(为简洁起见,简称

当我这样做时,options对象确实存在于useFetch内部,但是在useEffect结构内部却是空的。但是,url字符串在两种情况下都正确填充。

这对我来说毫无意义。也许有人知道为什么会这样吗?

1 个答案:

答案 0 :(得分:0)

下面的代码实现表明它可以按预期工作。

异步/等待已转换为Promise,但应具有相同的行为。

“内部使用提取” 被输出3次:

  1. 安装(useEffect(()=>..., []
  2. 第一次状态更改(setLoading(true)
  3. 第二次更改状态(setLoading(false)

“内部使用效果” 在挂载(useEffect(()=>..., [])上输出1次

由于这种方式对您不起作用,可能意味着在安装组件时,选项尚不可用。

当您说将选项作为依赖项放置时,您会对其进行确认,其中两次调用useEffect时,第一次获取失败(很可能是因为缺少选项)。

我很确定您会使用自定义钩子在组件的父级中找到选项问题。

const axios = {
    get: (url, options) => {
      return new Promise(resolve => setTimeout(() => resolve({ status: 200, data: 'Hello World' }), 2000));
    }
  };
  
  const AppContext = React.createContext({ app: null });
  
  const useFetch = (url, options) => {
    const [data, setData] = React.useState();
    const [loading, setLoading] = React.useState(true);
    const { app } = React.useContext(AppContext);
    console.log('** Inside useFetch: options = ', JSON.stringify(options));
  
    React.useEffect(() => {
      console.log('**** Inside useEffect: options = ', JSON.stringify(options));
      const fetchData = function () {
          setLoading(true);
          const response = axios.get(url, options)
            .then(response => {
              if (response.status === 200) {
                setData(response.data);
              }
              setLoading(false);
            })
            .catch(error => {
              setLoading(false);
              throw error;
            });

      };
      fetchData();
    }, []);
  
    return { loading, data };
  };
  
  const App = ({url, options}) => {
    const { loading, data } = useFetch(url, options);
    return (
      <div
          style={{
              display: 'flex', background: 'red',
              fontSize: '20px', fontWeight: 'bold',
              justifyContent: 'center', alignItems: 'center',
              width: 300, height: 60, margin: 5
          }}
      >
        {loading ? 'Loading...' : data}
      </div>
    );
  };
  
  ReactDOM.render(
    <App
        url="https://www.dummy-url.com"
        options={{ headers: { Authorization: 'eyJraWQiOiJVNW...' } }}
    />,
    document.getElementById('root')
  );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />