为什么我的自定义数据获取挂钩多次被调用?

时间:2020-10-10 15:13:56

标签: reactjs react-hooks rendering

我正在构建一个简单的网站,该网站可以在页面加载时从CMS获取内容。当我在组件内部使用React useState和useEffect钩子并记录状态变量content时,它的行为符合预期。但是,如果从中创建自定义挂钩,则数据将被提取两次。

当我在组件内部使用挂钩时,效果很好:

const AboutUsPage = () => {
   const [content, setContent] = useState(null);
   const [error, setError] = useState(null);
   const [loading, setLoading] = useState(true);
  
   useEffect(() => {
      const fetchData = async () => {
         try {
            const result = await client.getEntries({
               content_type: 'aboutUsPage',
                include: 10,
            });

            setData(result.items[0].fields);

         } catch (e) {
            setError(e);
         } finally {
            setLoading(false);
         }
    };

    fetchData();

  }, []);

  console.log(content);

  return (
     <>
        {content && <p>We have content!</p>}
     </>

  );

};

输出

null
{title: "About us Page", header: {…}}

这是我期望的,因为fetchData()是在首次安装组件之后调用的,然后再次使用数据进行渲染。但是,如果我创建一个自定义钩子,由于某种原因,数据将被提取两次。我以contentType作为依赖项和[]作为依赖项进行了尝试,但这似乎没有什么不同。我也已经禁用了React.StrictMode。

useData.js

const useData = (contentType) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const result = await client.getEntries({
          content_type: contentType,
          include: 10,
        });

        setData(result.items[0].fields);

      } catch (e) {
        setError(e);
      } finally {
        setLoading(false);
      }
    };

    fetchData();

  }, [contentType]);

  return [loading, error, data];
};

AboutUsPage.js

const AboutUsPage = () => {
  const [error, loading, content] = useData('aboutUsPage');

  console.log(content);

  return (
     <>
        {content && <p>We have content!</p>}
     </>

  );
}

输出

null
{title: "About us Page", header: {…}}
{title: "About us Page", header: {…}}

我真的不明白为什么或我可以做什么来解决这个问题。

1 个答案:

答案 0 :(得分:0)

您返回[加载,错误,数据]并返回[错误,加载,内容]的顺序有误。

发生在您身上的第一件事没有任何意义,因为最后您还设置了setLoading(false);

在某些情况下,通过useState挂钩进行的反应状态更新未组合到一个重新渲染中。您可以阅读有关here

的信息

我为您创建了一个codeSandbox示例,以说明这两种场景与自定义钩子无关,但两次调用setState code