首页 > 解决方案 > 一旦我提交表单并从输入字段中获取值并将其分配给 api url 并获得响应,我想使用 useEffect

问题描述

我正在尝试使用 API 制作 ip 跟踪器。我正在使用表单输入和 useState 从用户那里获取一个值并将其分配给 API ip 值。我正在使用自定义 useFetch 挂钩来使用来自的值获取数据state.我希望 useFetch 仅在提交表单或单击提交按钮时运行。但它最初呈现 null 并在我每次输入时呈现。我是新来的反应和从头开始学习。请指出我的错误。

这是我的 useFetch 钩子:

      import { useState, useEffect } from 'react';
    
    export const useFetch = (url, options, dep) => {
        const [response, setResponse] = useState(null);
        const [error, setError] = useState(null);
        const [isLoading, setIsLoading] = useState(false);
        useEffect(() => {
            const fetchData = async () => {
                setIsLoading(true);
                try {
                    const res = await fetch(url, options);
                    const json = await res.json();
                    setResponse(json);
                    setIsLoading(false);
                } catch (error) {
                    setError(error);
                }
            };
            fetchData();
        }, [dep]);
        return { response, error, isLoading };
    };

头文件:

import { useState } from 'react';
import { FaArrowRight } from 'react-icons/fa';
import React from 'react';
import { Form, FormInput, Head, HeadLine, Button } from './Header.elements';
import { useFetch } from '../../useFetch';

const Header = () => {
    const [value, setValue] = useState('');
    const [Ip, setIp] = useState(value);
    const API_KEY = 'at_xtpIidIz9vUqEzBODaUwtVRXf';
    const URL = `https://geo.ipify.org/api/v1?apiKey=${API_KEY}&ipAddress=${Ip}`;

    const handleSubmit = (e) => {
        e.preventDefault();
        setIp(value);
    };
    const { isLoading, response, dep } = useFetch(URL, '', setIp);

    console.log(response);

    const handleChange = (e) => {
        setValue(e.target.value);
    };
    return (
        <>
   
              {/* styled components */}

            <Head>
                   
                <HeadLine>IP Address Tracker</HeadLine>
                <Form onSubmit={handleSubmit}>
                    <FormInput
                        onChange={handleChange}
                        value={value}
                        placeholder='Search for any IP address or Domain'
                    />
                    <Button type='submit'>
                        <FaArrowRight />
                    </Button>
                </Form>
            </Head>
        </>
    );
};

export default Header;

App.js 文件:

import Header from './components/Header/Header';
import GlobalStyle from './globalStyles';

function App() {
    return (
        <>
            <GlobalStyle />
            <Header />
        </>
    );
}

export default App;

标签: reactjsapireact-hooksfetch-apiuse-effect

解决方案


React 钩子应该在每次组件渲染时运行,它在钩子规则中有所描述。您可能看到的是每次渲染的返回值。我敢肯定,如果您在浏览器中检查了您的网络选项卡,您只会看到 1 个来自useEffect的回调函数发出的请求fetch

我认为你已经混淆了useFetch依赖关系,因为setIp它是状态更新函数并且是一个稳定的引用,所以它永远不会触发useEffect钩子来重新运行回调。我认为您希望Ip状态值成为依赖项,即useFetch(URL, '', Ip);.

const { isLoading, response, error } = useFetch(URL, '', Ip);

钩子:您可能还想清除finally块中的加载状态,因此无论成功或失败,您都可以在不再主动获取数据时相应地更新您的 UI。我建议还传递多个依赖项,以防您有更多依赖项。这里的变化是只传递一个完整的依赖数组。

export const useFetch = (url, options, deps) => {
  const [response, setResponse] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      try {
        const res = await fetch(url, options);
        const json = await res.json();
        setResponse(json);
      } catch (error) {
        setError(error);
      } finally {
        setIsLoading(false);
      }
    };
    fetchData();
  }, deps); // <-- pass dependencies
  return { response, error, isLoading };
};

用法:这里定义了依赖数组

const { isLoading, response, error } = useFetch(URL, '', [Ip]);

推荐阅读