简体   繁体   English

在 React 组件之间共享数据

[英]Sharing data between React components

I have a search form in React that performs an API call and saves the data called nameservers in-state using the useState() React hook.我在 React 中有一个搜索表单,它执行 API 调用并使用 useState() React 挂钩将名为名称服务器的数据保存在状态。

I'm trying to determine how I can pass this data to another component so the data can be used for rendering elsewhere on the page.我正在尝试确定如何将这些数据传递给另一个组件,以便可以将数据用于在页面上的其他位置呈现。

Currently, I'm just outputting the data in my return block which appears below the search form.目前,我只是在搜索表单下方显示的返回块中输出数据。

import React, { useState } from "react";
import { Spinner, Form, Button, Container, Col } from "react-bootstrap";
import { FaSearch } from "react-icons/fa";

const SearchForm: React.FC = () => {
  const [domain, setDomain] = useState("");
  const [loading, setLoading] = useState(false);
  const [nameservers, setNameservers] = useState([]);
  const [submitted, setSubmitted] = useState(false);

  const formText = "Search for a domains";

  const handleChange = (event: any) => {
    setDomain(event.target.value);
  };

  const handleSubmit = (event: any) => {
    event.preventDefault();
    setLoading(true);
    setSubmitted(true);
    console.log(domain);

    fetch(`https://dns.google.com/resolve?name=${domain}&type=NS`)
      .then(results => results.json())
      .then(data => {
        setLoading(false);
        if (data && data.Answer) {
          data.Answer.sort((a: any, b: any) => a.data.localeCompare(b.data));
          setNameservers(data.Answer);
        }
      });
  };

  return (
    <>
      <Form onSubmit={handleSubmit}>
        <Form.Row>
          <Col />
          <Col>
            <Form.Control
              type="text"
              placeholder={formText}
              value={domain}
              onChange={handleChange}
              autoFocus
              required
            />
          </Col>
          <Col>
            <Button variant="primary" type="submit">
              <FaSearch /> Search
            </Button>
          </Col>
        </Form.Row>
      </Form>
      <hr />
      {submitted &&
        nameservers.map((server: any, index: number) => (
          <li key={index}>{server.data}</li>
        ))}

      {submitted && nameservers.length === 0 && <small>Error</small>}

      {loading && (
        <Container className="text-center">
          <Spinner animation="grow" size="sm" />
          <Spinner animation="grow" size="sm" />
          <Spinner animation="grow" size="sm" />
        </Container>
      )}
    </>
  );
};

export default SearchForm;

There are multiple ways to share data between components.有多种方法可以在组件之间共享数据。 You can use one of the following options:您可以使用以下选项之一:

  • If the component to which you want to pass the data is a child of SearchForm component, then you can pass it as a prop .如果要向其传递数据的组件是SearchForm组件的子组件,则可以将其作为prop传递。

  • If you are managing state via redux, you can connect components to the redux store and get the required data from the redux store in your components. If you are managing state via redux, you can connect components to the redux store and get the required data from the redux store in your components.

  • You can also use React's Context API to share common data between components that may or may not have a parent-child relationship.您还可以使用 React 的Context API在可能具有或不具有父子关系的组件之间共享公共数据。

  • If the component that needs the data from SearchForm component, is a parent component of SearchForm component, you can pass a callback function to the SearchForm component as a prop and when data is available in SearchForm component, call the callback function, received as a prop , and pass the data as an argument to that callback function.如果需要SearchForm组件数据的组件是SearchForm组件的父组件,可以将回调function作为prop传递给SearchForm组件,当SearchForm组件中有数据时,调用回调function,作为prop接收,并将数据作为参数传递给该回调 function。

I'd do what Yousaf suggested.我会按照优素福的建议去做。

SearchForm should have two props: nameservers handleSubmit SearchForm 应该有两个道具:nameservers handleSubmit

(This will make it easy to write a Storybook story and any tests). (这将使编写 Storybook 故事和任何测试变得容易)。

Then make a wrapper for SearchForm that does the API call (handleSubmit) and sets nameservers in context.然后为 SearchForm 创建一个包装器,该包装器执行 API 调用 (handleSubmit) 并在上下文中设置名称服务器。 Now nameservers can be accessed elsewhere in the app.现在可以在应用程序的其他地方访问名称服务器。

Ciao, when I want to share data between components I use React-Redux . Ciao,当我想在组件之间共享数据时,我使用React-Redux Lets make an example: Suppose that you want to share data received by server (nameservers).让我们举个例子:假设您要共享服务器(名称服务器)接收到的数据。 At first install react-redux:首先安装 react-redux:

npm install react-redux
npm install redux
npm install @reduxjs/toolkit

Now we have to create the reducer and the action : Lets say you have your component in a folder called "/components/MyComponent".现在我们必须创建reduceraction :假设您将组件放在一个名为“/components/MyComponent”的文件夹中。 Create a file called MyReducer.js.创建一个名为 MyReducer.js 的文件。

/components/MyComponent/MyReducer.js /components/MyComponent/MyReducer.js

import { createReducer } from '@reduxjs/toolkit';

const initialState = {
  nameservers: undefined,
};

const LoginReducer = createReducer(initialState, {
   ["SET_NAMESERVERS"]: (state, action) => {
       state.nameservers= action.payload.nameservers;
   },
})

export default MyReducer;

Now, on the same folder, createa file called MyAction.js现在,在同一个文件夹中,创建一个名为 MyAction.js 的文件

/components/MyComponent/MyAction.js /components/MyComponent/MyAction.js

export const setNameServers = data => ({
   type: "SET_NAMESERVERS",
   payload: { nameservers: data }
});

Then create the store : On your project root create a folder callled redux .然后创建store :在您的项目根目录上创建一个redux的文件夹。 Inside this create a folder called store .在其中创建一个名为store的文件夹。 Then on this folder create a file called index.js.然后在这个文件夹上创建一个名为 index.js 的文件。

redux/store/index.js redux/store/index.js

import { createStore, combineReducers } from "redux";
import MyReducer from '../../components/MyComponent/MyReducer';

const reducers = combineReducers({
  MyReducer,
});

const store = createStore(reducers);

export default store;

Now on index.js file on root folder lets pass the store already created:现在在根文件夹上的 index.js 文件中,让我们传递已经创建的商店:

index.js index.js

...
import { Provider } from 'react-redux';
import store from "./redux/store";

ReactDOM.render((
 <Provider store={store}>
    <App />
 </Provider>
), document.getElementById('root') || document.createElement('div'));

We have almost done.我们几乎完成了。 On your component (MyComponent) you retrieve data from server.在您的组件 (MyComponent) 上,您从服务器检索数据。 Once you have data, lets dispatch data to share into the store :获得数据后,让我们将数据发送到 store 中共享

/components/MyComponent/MyComponent.js /components/MyComponent/MyComponent.js

...
import { useDispatch } from 'react-redux';
import { setNameServers } from './MyComponentAction';

const MyComponent: React.FC = () => {
   const [nameservers, setNameservers] = useState([]);
   const dispatch = useDispatch();
   ....
   const handleSubmit = (event: any) => {
     ...

fetch(`https://dns.google.com/resolve?name=${domain}&type=NS`)
.then(results => results.json())
.then(data => { 
  setLoading(false);
  if (data && data.Answer) {
    data.Answer.sort((a: any, b: any) => a.data.localeCompare(b.data));
    setNameservers(data.Answer);
    dispatch(setNameServers(data.Answer)); // here the magic
  } 
  });
 };
   
};

Done: now you have nameservers on your react redux store and you can easly get it from another component like this:完成:现在您的 react redux 商店中有名称服务器,您可以轻松地从另一个组件中获取它,如下所示:

OtherComponent.js其他组件.js

import { useSelector } from 'react-redux';
const OtherComponent: React.FC = () => {
   const nameservers = useSelector(state => state.MyReducer.nameservers);
};

And if you log nameservers somewhere in OtherComponent you will see data retrieved in MyComponent .如果您在OtherComponent中的某处记录名称服务器,您将看到在MyComponent中检索到的数据。 Awesome!惊人的!

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

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