简体   繁体   English

React 自定义钩子不会从第一次点击更新

[英]React custom hook is not updating from first click

I've created a custom hook to fetch data with events handlers, when I using it on click event the hook makes the request on the second click我创建了一个自定义挂钩来使用事件处理程序获取数据,当我在单击事件上使用它时,挂钩在第二次单击时发出请求

useFetch.js使用Fetch.js

import { useState, useEffect } from 'react';
import { makeRequest } from '../utils';

const useFetch = (query = {}) => {
  const [request, setRequest] = useState({ ...query });

  const [data, setData] = useState({
    response: null,
    isError: null,
    isLoading: request.isLoading,
  });

  const fetchData = async () => {
    if (!request.url) {
      return;
    }
    try {
      const res = await makeRequest(
        request.url,
        request.method || 'get',
        request.body || null,
      );
      setData({
        response: res,
        isLoading: false,
        error: null,
      });
    } catch (error) {
      setData({
        response: null,
        error,
        isLoading: false,
      });
    }
  };
  const onEvent = (req) => {
    if (req) {
      setRequest({ ...req });
    }
  };

  useEffect(() => fetchData(), [request]);

  return { ...data, onEvent };
};

export default useFetch;

Component File组件文件

const { isLoading, isError, response, onEvent } = useFetch();

  const ClickMe = () => {
    onEvent({
      url: 'v1/profile/login',
      method: 'post',
      body: {
        username: 'eee@ddd.com',
        password: '2342332',
      },
    });
    console.log('response', response);
  };
return (
    <>
      <button onClick={() => ClickMe()} type="button">
       
        Click Me
      </button>
    )

the log inside the ClickMe function is null in the first click but in the second click it returns the value ClickMe function 内的日志在第一次单击时为 null 但在第二次单击时返回值

Because fetchData is asynchronous function you cannot know when resposne will be set, that's why you cannot access it like normal sync code因为fetchData是异步的 function 你不知道什么时候会设置resposne ,这就是为什么你不能像普通同步代码一样访问它

in your app code you could observe response change to console it like在您的应用程序代码中,您可以观察到response更改以控制它

useEffect(() => { console.log(response) }, [ response ]);

At the time of console.log, the response is not fetched.在 console.log 的时候,没有获取响应。 Since when ever response changes, the component re-renders, you can try like below to see the updated values of isLoading and response .因为当response发生变化时,组件会重新渲染,您可以尝试如下所示查看isLoadingresponse的更新值。

return (
  <>
    {isLoading && <div> Loading... </div>}
    {`Resonse is ${JSON.stringify(response)}`}
    <button onClick={() => ClickMe()} type="button">
      Click Me
    </button>
  </>
);

As the others said, it's an asynchronous operation.正如其他人所说,这是一个异步操作。 If you want to use the response as soon as you called onEvent, you can do something along these lines using a promise:如果您想在调用 onEvent 后立即使用响应,您可以使用 promise 执行以下操作:

import { useState, useEffect } from 'react';
import { makeRequest } from '../utils';

const useFetch = (query = {}) => {
  useEffect(() => {
    if (query) {
      fetchData(query)
    }
  }, []) // if query is provided, run query

  const [data, setData] = useState({
    response: null,
    isError: null,
    isLoading: true
  });
  
  const fetchData = async (query) => {
    return new Promise((resolve, reject) => {
      if (!query.url) {
        reject('url needed')
      }
      makeRequest(query).then(res => {
        setData({
          response: res,
          isLoading: false,
          error: null
        })
        resolve(res)
      ).catch(error => {
          setData({
            response: null,
            error,
            isLoading: false
          });
          reject(error)
        });
      })
    })
  };

  // provide fetchData directly for lazy calls
  return { ...data, fetchData };
};

export default useFetch;

And then call it like so:然后这样称呼它:


const { response, fetchData } = useFetch()

fetchData({
      url: 'v1/profile/login',
      method: 'post',
      body: {
        username: 'eee@ddd.com',
        password: '2342332',
      },
    }).then(res => ...);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM