【问题标题】:How to refetch data when field change with react hooks使用反应挂钩更改字段时如何重新获取数据
【发布时间】:2020-05-15 10:28:34
【问题描述】:

我的组件通过调用包含通过 API 请求的逻辑的钩子文件来获取数据。 默认情况下,它将调用 API,无需任何额外参数。 在 GUI 中,我还显示了一个输入,用户可以在其中输入文本。 每次他写一封信我都想重新获取数据。但我不太确定如何使用 react 和 hooks 来做到这一点。

我声明了“useEffect”。我看到输入的内容发生了变化。但还有什么?我不能从那里调用钩子函数,因为我得到了这个错误:

“不能在回调中调用 React Hook “useFetch”。必须在 React 函数组件或自定义 React Hook 函数 react-hooks/rules-of-hooks 中调用 React Hooks”

这是代码:

hooks.js

import { useState, useEffect } from "react";
function useFetch(url) {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchUrl() {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
        setLoading(false);
      }
    fetchUrl();
  }, [url]);
  return [data, loading];
}
export { useFetch };

mycomponent.js

import React, { useState, useEffect } from 'react';
import { useFetch } from "../hooks";    

const MyComponent = () => { 

useEffect(() => {
    console.log('rendered!');
    console.log('searchTerm!',searchTerm);
});

const [searchTerm, setSearchTerm] = useState('');
const [data, loading] = useFetch(
    "http://localhost:8000/endpoint?${searchTerm}"
  );
  return (
    <>
      <h1>Users</h1>
      <p>
        <input type="text" placeholder="Search" id="searchQuery" onChange={(e) => setSearchTerm(e.target.value)} />
      </p>
      {loading ? (
        "Loading..."
      ) : (
        <div>
          {data.users.map((obj) => (
            <div key={`${obj.id}`}>
              {`${obj.firstName}`} {`${obj.lastName}`}
            </div>
          ))}
        </div>
      )}
    </>
  );
}

export default MyComponent;

【问题讨论】:

  • 您是否尝试将其导出为默认值?
  • 是的,它仍然给出同样的错误。

标签: reactjs react-hooks


【解决方案1】:

创建一个函数来处理您的 onChange 事件并从中调用您的 fetch 函数。像这样的:

mycomponent.js

import React, { useState, useEffect } from 'react';
import { useFetch } from "../hooks";    

const MyComponent = () => { 

useEffect(() => {
    console.log('rendered!');
    console.log('searchTerm!',searchTerm);
});

const [searchTerm, setSearchTerm] = useState('');


const handleChange = e => {
   setSearchTerm(e.target.value)
   useFetch(
    "http://localhost:8000/endpoint?${searchTerm}"
  );
}

const [data, loading] = useFetch(
    "http://localhost:8000/endpoint?${searchTerm}"
  );
  return (
    <>
      <h1>Users</h1>
      <p>
        <input type="text" placeholder="Search" id="searchQuery" onChange={(e) => handleChange(e)} />
      </p>
      {loading ? (
        "Loading..."
      ) : (
        <div>
          {data.users.map((obj) => (
            <div key={`${obj.id}`}>
              {`${obj.firstName}`} {`${obj.lastName}`}
            </div>
          ))}
        </div>
      )}
    </>
  );
}

export default MyComponent;

【讨论】:

  • 它还在抱怨。现在它说:React Hook "useFetch" 在函数 "handleChange" 中被调用,它既不是 React 函数组件也不是自定义 React Hook 函数 react-hooks/rules-of-hooks
  • 将此块:async function fetchUrl() { const response = await fetch(url); const json = await response.json(); setData(json); setLoading(false); } 移到 useEffect 挂钩之外。
  • 我现在将 UseFetch 大写并将其导出为默认值。然后它给出了错误:只能在函数组件的主体内部调用 Hooks。这可能由于以下原因之一而发生
  • 不,不要那样做,请参阅我上面的评论 - React 不会让您从其他地方调用您定义的函数 inside useEffect 钩子。在 useEffect 钩子上方定义您的 fetchUrl 并然后调用它
  • 运气不好。我正在运行反应 16.12.0。尝试大写和不使用。 async 函数在 useEffect 之外。但仍然是同样的错误。
【解决方案2】:

您的代码根据您的要求为我工作,在文本框中输入 1 或 2 您将得到不同的结果。

所以基本上 API 会使用默认值“searchTerm”调用一次,然后每次都由 onChange 调用。

在当地试试这个 -

import React, { useState, useEffect } from "react";
function useFetch(url) {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchUrl() {
      const response = await fetch(url);
      const json = await response.json();
      setData(json);
      setLoading(false);
    }
    fetchUrl();
  }, [url]);
  return [data, loading];
}
export { useFetch };

const MyComponent = () => {
  useEffect(() => {
    console.log("rendered!");
    console.log("searchTerm!", searchTerm);
  });

  const [searchTerm, setSearchTerm] = useState("");
  const [data, loading] = useFetch(
    `https://reqres.in/api/users?page=${searchTerm}`
  );

  return (
    <>
      <h1>Users</h1>
      <p>
        <input
          type="text"
          placeholder="Search"
          id="searchQuery"
          onChange={e => setSearchTerm(e.target.value)}
        />
      </p>
      {loading ? (
        "Loading..."
      ) : (
        <div>
          {data.data.map(obj => (
            <div key={`${obj.id}`}>
              {`${obj.first_name}`} {`${obj.last_name}`}
            </div>
          ))}
        </div>
      )}
    </>
  );
};

export default MyComponent;

【讨论】:

    【解决方案3】:

    您的 useFetch 挂钩的设置方式只会在加载时运行一次。您需要以一种可以从仅在 searchTerm 更改时运行的效果函数触发它的方式对其进行设置。

    【讨论】:

      【解决方案4】:

      这就是您处理搜索以做出正确反应的方式。最好在用户登陆您的页面时定义默认的 searchTerm,否则他们将看到空白页面或看到“加载”文本,这不是良好的用户体验。

        const [data, setData] = useState([]);
        const [searchTerm, setSearchTerm] = useState("defaultTerm")
      

      在页面的第一次渲染中,我们应该向用户显示“defaultTerm”搜索的结果。但是,如果您不设置保护,则在每次击键时,您的应用都会发出 api 请求,这会降低您的应用速度。

      为避免在每次击键时获取数据,我们将“setTimeout”设置为可能 500 毫秒。那么每次用户输入不同的搜索词时,我们必须确保我们清理了之前的 setTimeout 函数,这样我们的应用就不会出现内存泄漏。

      useEffect(() => {
          async function fetchUrl() {
            const response = await fetch(url);
            const json = await response.json();
            setData(json);
          }
         
         // this is during initial rendering. we have default term but no data yet
         if(searchTerm && !data){
              fetchUrl();
         }else{ 
              //setTimeout returns an id
              const timerId=setTimeout(()=>{
                  if(searchTerm){
                     fetchUrl}
               },500)
      
          // this where we do clean up
         return ()=>{clearTimeout(timerId)}
         }
         
        }, [url]);
        return [data, loading];
      }
      

      在 useEffect 中,我们只允许返回一个负责清理的函数。所以在我们再次调用 useEffect 之前,我们停止了最后的 setTimeout。

      【讨论】:

        猜你喜欢
        • 2020-02-18
        • 1970-01-01
        • 2021-01-27
        • 2020-06-18
        • 2019-07-31
        • 2020-04-04
        • 2021-06-23
        • 2020-09-12
        • 2021-10-02
        相关资源
        最近更新 更多