在另一个组件中单击按钮时触发 Axios 数据获取

trigger Axios data fetch on button click in another component

我有这样的组件结构

src
 --App
   --DataTableComponent
   --ButtonComponnet
axios
 --useAxios

在应用程序加载时,我调用 DataTableComponent 中的 Axios 库(通过自定义钩子 useAxios)来获取一些数据,稍后当用户单击 [=14= 中的按钮时] 我想 AxiosDataTableComponent 中再次加载数据,但我不确定组件是兄弟姐妹。

您可以只发送一些道具变量或函数,它们会 return 为真或单击按钮时的其他内容。 ButtonComponnent 是在 DataTable Component 还是其他地方调用的?

如果我的理解正确的话,您要做的是让两个同级组件相互通信和调用函数。如果他们是兄弟姐妹,我建议使用第三方库,如 Redux 或 EventHub

如果组件 A 具有函数“updateData”,那么您可以使用 Redux 在组件 B 中调用它,方法是设置一个名为“updateData”的 reducer,并让 DataTableComponent 订阅“data”

Redux 文件:

import { createStore, combineReducers } from "redux";

const reducer = (state = {}, action) => {
  ... {axios fetch here}
};

const store = createStore(reducer);
export default store;

DataTableComponent.jsx:

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import axios from "axios";
import { updateData } from "../redux/actions";

 const DataTableComponent = () => {

  const data = useSelector(state => state.data);

  const dispatch = useDispatch();

  const fetchData = () => dispatch(updateData());

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>

      <table>{data.map((item, index) => <tr key={index}><td>{item.id}</td><td>{item.name}</td></tr>)}</table>
    </div>
  );
};

ButtonComponent.jsx:

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import axios from "axios";
import { updateData } from "../redux/actions";

 const ButtonComponent = () => {

  const data = useSelector(state => state.data);

  const dispatch = useDispatch();

  const fetchData = () => dispatch(updateData());

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>

      <table>{data.map((item, index) => <tr key={index}><td>{item.id}</td><td>{item.name}</td></tr>)}</table>
    </div>
  );
};

在您的情况下,您要做的是提升状态。这里有一个link到official react documentation

此外,我所做的是针对您的特定情况创建了一个代码沙箱示例,以演示如何在您的应用中执行类似的操作。这是该代码沙箱 https://codesandbox.io/s/romantic-brook-sfvpd?file=/src/App.tsx

的 link

提升状态背后的原则是,如果您有 2 个或更多组件必须共享信息,则将该信息提升一个级别到它们的父级。所以,正如您在代码沙箱中看到的那样,我所做的是应用程序组件现在获取信息并将其向下推送到您的数据 table 组件。

因此,您需要 useAxios 挂钩存在于您的父应用程序组件中。按钮组件的工作是简单地触发获取。

一旦触发提取,return新数据将由 useAxios 挂钩编辑。

提取还会导致应用程序的 useEffect 挂钩到 运行,这会更新状态并将数据推送到数据 table 组件。

因此,在您的情况下,您可能希望将 useAxios 挂钩包装在您自己的自定义挂钩中,这样您就可以传递参数,而这些参数又可以让您的 useAxios 挂钩从中获取数据你的 API.

继续点击获取数据按钮,每次我 return 一个随机数量的项目,这样你就会看到你的数据组件数据得到更新。请记住打开控制台以查看调用 useAxios 挂钩,然后是正在更新的数据 table 内容。

我在我的一些生产应用程序中使用了类似的方法,并且在这些应用程序中我围绕 useSWR hooks

创建了类似的自定义包装器

如果您有必须跨应用程序共享的数据,即全局数据,那么使用 redux 或类似的东西是个好主意,但特定于几个组件的数据不需要这种方法,然后应该使用“提升状态”的做事方式。

为了完整起见,下面还给出了代码。

import { useEffect, useState } from "react";
import "./styles.css";

// useAxios hook
const useAxios = (_: boolean) => {
  console.log("useAxios");

  // mock data
  const arr = [
    {
      name: "Bianca Paul",
      phone: "1-453-676-9140",
      email: "mollis.integer@google.ca",
      address: "221-3571 Nam Street",
      id: 8
    },
    {
      name: "Hadley Gordon",
      phone: "1-235-486-3229",
      email: "adipiscing.mauris@icloud.com",
      address: "3255 Nec, Road",
      id: 3
    },
    {
      name: "Irma Bryan",
      phone: "1-818-417-5465",
      email: "ornare.in@icloud.net",
      address: "136-222 Facilisis Rd.",
      id: 2
    },
    {
      name: "Simon Nash",
      phone: "1-872-216-6482",
      email: "enim.nec@aol.couk",
      address: "Ap #873-5860 Erat St.",
      id: 101
    },
    {
      name: "Ursula Fleming",
      phone: "(998) 407-7291",
      email: "semper.erat@protonmail.com",
      address: "110-1550 Phasellus Ave",
      id: 43
    }
  ];

  // Randomize the data
  function getRandomItem() {
    // get random index value
    let randomIndex = Math.floor(Math.random() * arr.length);
    if (randomIndex === 0) randomIndex = 1;
    // get random items
    const item = arr.slice(0, randomIndex);

    return item;
  }

  // return a promise
  const data = new Promise<any>((resolve, reject) => {
    setTimeout(() => {
      return resolve(getRandomItem());
    }, 1000);
  });

  return { data };
};

// Button component
const ButtonComponent = (props: { clickCallback: () => void }) => {
  return (
    <>
      <button onClick={props.clickCallback}>fetch data</button>
    </>
  );
};

// DataComponent
const DataTableComponent = ({
  data
}: {
  data:
    | [
        {
          name: string;
          phone: string;
          email: string;
          address: string;
          id: string;
        }
      ]
    | null;
}) => {
  return (
    <>
      {data ? (
        data.map((v) => (
          <div key={v.id}>
            {v.name},{v.address}, {v.phone}
          </div>
        ))
      ) : (
        <span>loading</span>
      )}
    </>
  );
};

// App Parent component
export default function App(): JSX.Element {
  const [fetch, setFetch] = useState(true);
  const [returnedData, setReturnedData] = useState<
    | [
        {
          name: string;
          phone: string;
          email: string;
          address: string;
          id: string;
        }
      ]
    | null
  >(null);
  const { data } = useAxios(fetch);
  const buttonClicked = () => {
    setFetch(true);
  };

  useEffect(() => {
    let isMounted = true;
    if (fetch) {
      (async () => {
        if (isMounted) setReturnedData(await data);
        if (isMounted) setFetch(false);
        console.log(await data);
      })();
    }
    return function () {
      isMounted = false;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fetch]);

  return (
    <div className="App">
      <h1>Lift state up</h1>
      <div>
        <DataTableComponent data={returnedData} />
      </div>
      <div>
        <ButtonComponent clickCallback={buttonClicked} />
      </div>
    </div>
  );
}