繁体   English   中英

反应钩子 useEffect 以在按钮单击时获取数据(打字稿)

[英]react hook useEffect to fetch data on button click (typescript)

我有一个组件,我想使用 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 function 使用钩子 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];
};

使用此代码获取页面加载时开始,但我只想在按钮单击时获取数据。 我怎样才能做到这一点?

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];
};

The useDataApi hook returns [,doFetch] , but the doFetch is actually setUrl so if you wanted that to work as expected you can let the initial value for the url be null or falsey and only allow a fetch inside the effect when the url is valid /实话。 当您单击按钮时,即是您 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];
};

虽然,更好的解决方案是在按钮单击时直接调用 function 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

暂无
暂无

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

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