【问题标题】:react hook useEffect to fetch data on button click (typescript)反应钩子 useEffect 以在按钮单击时获取数据(打字稿)
【发布时间】:2021-05-10 22:05:06
【问题描述】:

我有一个组件,我想使用 react hook useEffect 在按钮单击时获取 isbn 数据,在路由 ${basicUrl}/editorials/${isbn} 上执行 get,所以我编写了这个组件:

import React, { Fragment, useState } from "react";
import "./Home.css";
import { V3_BASIC_URL } from "../../constants/endpoints";
import { useDataApi } from "../../store/effects/dataEffects";

import SearchIsbnElement from "../../components/SearchIsbnElement/SearchIsbnElement";
import IsbnPanelElement from "../../components/IsbnPanelElement/IsbnPanelElement";

function Home() {
  const [query, setQuery] = useState<string>("9788808677853");
  const [isValid, setIsValid] = useState<boolean>(true);

  const url = `${V3_BASIC_URL(
    process.env.REACT_APP_API_ENV
  )}/editorials/${query}`;
  const [{ isbn, isLoading, isError }, doFetch] = useDataApi(url, {
    isLoading: false,
    isError: false,
    isbn: undefined,
  });

  const buttonCallback = () => {
    doFetch(url);
  };
  const isbnRegexp = /^97\d{11}$/
  const validateQuery = (query: string): boolean => isbnRegexp.test(query)

  const inputCallback = (query: string) => {
    setQuery(query)
    setIsValid(validateQuery(query));
  };

  return (
    <div id="isbn-panel-home" className="Home">
      <SearchIsbnElement
        inputCallback={inputCallback}
        buttonCallback={buttonCallback}
        query={query}
        isValid={isValid}
      ></SearchIsbnElement>
      {isError && <div>Il servizio al momento non è disponibile, riprova più tardi</div>}
      {isLoading ? (
        <div>Loading ...</div>
      ) : (
        !isError && 
        <Fragment>
          <IsbnPanelElement isbn={isbn}></IsbnPanelElement> 
          <p>{isbn?.scheda_volume == null && 'isbn non trovato'}</p>
        </Fragment>
      )}
    </div>
  );
}

export default Home;

useDataApi 函数使用钩子 useEffect 并返回 statesetUrl 操作以在 isbn 值更改时设置新 url。这是useDataApi 文件:

import { useState, useEffect, useReducer } from "react";

import {
  dataFetchFailure,
  dataFetchInit,
  dataFetchSuccess,
} from "../actions/dataActions";
import { dataFetchReducer, ISBNState } from "../reducers/dataReducers";
import { get } from "../../tools/request";

type InitialState = {
  isLoading: boolean,
  isError: boolean,
  isbn: undefined,
}

export const useDataApi = (initialUrl: string, initialData: InitialState) : [ISBNState, (value: string) => void]  => {
  const [url, setUrl] = useState(initialUrl);

  const [state, dispatch] = useReducer(dataFetchReducer, initialData);

  useEffect(() => {
    let didCancel: boolean = false;

    const fetchData = async (): Promise<any> => {
      dispatch(dataFetchInit());
      const options = {
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json'
        },
        auth: {
          username: `${process.env.REACT_APP_API_AUTH_USER}`,
          password: `${process.env.REACT_APP_API_AUTH_PWD}`
        }
      }
      try {
        const {data} = await get(url, options);
        if (!didCancel) {
          dispatch(dataFetchSuccess(data));
        }
      } catch (error) {
        if (!didCancel) {
          dispatch(dataFetchFailure(error));
        }
      }
    };

    fetchData();

    return () => {
      didCancel = true;
    };
  }, [url]);

  return [state, setUrl];
};

在页面加载时开始获取此代码,但我只想在单击按钮时获取数据。我该怎么做?

【问题讨论】:

    标签: javascript reactjs typescript react-hooks use-effect


    【解决方案1】:

    useEffect() 是一个通过不同的生命周期方法操作组件的钩子。为了在 onClick 上做某事,您需要为此创建一个方法:

    const fetchData = async (): Promise<any> => {
      dispatch(dataFetchInit());
      const options = {
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json'
        },
        auth: {
          username: `${process.env.REACT_APP_API_AUTH_USER}`,
          password: `${process.env.REACT_APP_API_AUTH_PWD}`
        }
      }
      try {
        const {data} = await get(url, options);
        if (!didCancel) {
          dispatch(dataFetchSuccess(data));
        }
      } catch (error) {
        if (!didCancel) {
          dispatch(dataFetchFailure(error));
        }
      }
    };
    

    只要这样做,你就会没事的

    编辑:useDataApi的新版本

    export const useDataApi = (
      url: string,
      initialData: InitialState
    ): [ISBNState, (value: string) => void] => {
      const [state, dispatch] = useReducer(dataFetchReducer, initialData);
    
      const fetchData = useCallback(async (): Promise<any> => {
        dispatch(dataFetchInit());
        const options = {
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
          },
          auth: {
            username: `${process.env.REACT_APP_API_AUTH_USER}`,
            password: `${process.env.REACT_APP_API_AUTH_PWD}`,
          },
        };
        try {
          const { data } = await get(url, options);
          dispatch(dataFetchSuccess(data));
        } catch (error) {
          dispatch(dataFetchFailure(error));
        }
      }, [url]);
    
      return [state, fetchData];
    };
    

    【讨论】:

      【解决方案2】:

      useDataApi 钩子返回[,doFetch],但doFetch 实际上是setUrl,所以如果您希望它按预期工作,您可以让 url 的初始值为 null 或 false,并且只允许获取当 url 有效/真实时在效果内。当您单击按钮时,即是您 setUrl 的时间,此时效果将允许出现 fetchData,因为届时将设置 url 的值。

      export const useDataApi = (initialUrl: string, initialData: InitialState): [ISBNState, (value: string) => void] => {
        // make this default to null here, or where you intende to use this hook 
        const [url, setUrl] = useState(null);
      
        // custom hook body
      
        useEffect(() => {
          // effect body
          if (url) {
            fetchData();
          }
          // hook cleanup
        }, [url]);
      
        return [state, setUrl];
      };
      

      虽然,更好的解决方案是在按钮点击时直接调用函数fetchData。一种方法是修改useDataApi 挂钩以直接返回“fetchData”,允许它接受url 作为参数并完全消除对const [url,setUrl] = useState(initialUrl) 的需要

      export const useDataApi = (initialUrl: string, initialData: InitialState): [ISBNState, (value: string) => void] => {
        const [state, dispatch] = useReducer(dataFetchReducer, initialData);
      
        const fetchData = useCallback(async (url): Promise<any> => {
          dispatch(dataFetchInit());
          const options = {
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
            },
            auth: {
              username: `${process.env.REACT_APP_API_AUTH_USER}`,
              password: `${process.env.REACT_APP_API_AUTH_PWD}`,
            },
          };
          try {
            const { data } = await get(url, options);
            if (!didCancel) {
              dispatch(dataFetchSuccess(data));
            }
          } catch (error) {
            if (!didCancel) {
              dispatch(dataFetchFailure(error));
            }
          }
        }, []);
      
        return [state, fetchData];
      };
      

      你也可以从钩子useDataApi中删除initialUrl

      【讨论】:

      • 如果我将initialUrl 更改为url,因为我不再使用initialUrl,我不需要在fetchData 中使用url 参数。我也需要在 useCallback 中设置缺少的依赖项url
      • 对于我添加的第二个代码 sn-p,您不需要将 url 添加到回调中,它不是那个依赖项,因为 url 来自函数的参数。
      猜你喜欢
      • 2021-02-15
      • 1970-01-01
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 2020-12-20
      相关资源
      最近更新 更多