UseEffect 在初始渲染时触发

UseEffect firing on initial render

我正在为 API 创建一个前端,要求用户输入 API 密钥和设备名称。问题是 UseEffect() 提取是使用 'undefined' 作为呈现上的 API 键触发的,因此 API 抛出 401 错误代码并阻止页面呈现,因此用户可以输入密钥。

见下面的代码:

Api.js

const Api = ({ device, key }) => {

    const [data, setData] = useState(null);
    

    useEffect(() => {
        fetch(`APILINK&key=${key}&id=${device}`)
        .then((res) => res.json())
        .then(setData)
    }, [device, key])

    if (data) return (
        <>
            <tbody>
                <tr>
                    <th>Date</th>
                    <th>Temp</th>
                    <th>C02</th>
                </tr>
                {data.samples.map((item) => (
                    <tr>
                        <td>{item.time}</td>
                        <td>{item.data[0]}</td>
                        <td>{item.data[1]}</td>
                    </tr>
                ))}
            
            </tbody>
        </>
    )
    return <div>No Data Found</div>
}

Home.js

const Home = ({ setDevice, setKey }) => {

    const getData = (e) => {
        e.preventDefault();
        const newDevice = e.target.deviceID.value;
        const apiKey = e.target.apiKey.value;
        setDevice(newDevice);
        setKey(apiKey);
    }

    return (
        <>
            <h1>Type in a device and provide an API key below:</h1>
            <form onSubmit={getData}>
                <input type='text' placeholder="Enter Device..." id='deviceID'></input>
                <input style={{display: 'block'}} type='text' placeholder="Enter API Key..." id='apiKey'></input>
                <button>Search</button>
            </form>
        </>

    )
}

export default Home;

App.js

const App = () => {

  const [device, setDevice] = useState()
  const [key, setKey] = useState()

  return (
    <>
      <Home setDevice={setDevice} setKey={setKey} />
      <Api device={device} key={key} />   
    </>
  )
}

export default App;

感谢任何帮助!!

您可以等到 key & device 道具可用:

useEffect(() => {
    key && device && fetch(`APILINK&key=${key}&id=${device}`)
        .then((res) => res.json())
        .then(setData)
}, [device, key])

useEffect 在第一次渲染后立即调用,不管依赖数组如何,所以上面的保护不会 运行 fetch 调用,直到这些变量可用(当依赖数组“看到”有变化并调用 useEffect 回调)。

如果 key 道具可能需要一段时间才能使用,您可能想要显示一个 loader


我建议 de-couple 从 useEffect 获取数据的逻辑,因为你可能想直接调用 getData,而且它也更适合测试和一般代码顺序.

const getData = (key, device) => 
    key && device && fetch(`APILINK&key=${key}&id=${device}`)
        .then((res) => res.json())
        .then(setData);

useEffect(() => {
    getData(key, device)
}, [device, key])

此外,useState(null) 中的 null 也没有必要,因为 useState() 的行为相同。

您可以将 fetch 放在 if 语句中

useEffect(() => {
        if(key && device){
          fetch(`APILINK&key=${key}&id=${device}`)
          .then((res) => res.json())
          .then(setData)
        }
    }, [device, key])

如果您打算在渲染时加载数据而不是之后加载更多数据,我将对您的 useEffect 挂钩进行以下更改:

 useEffect(() => {
        if(!device || !key || data) return null
        fetch(`APILINK&key=${key}&id=${device}`)
        .then((res) => res.json())
        .then(setData)
    }, [data, device, key])