如何在React中使用上下文将数据从一个组件发送到另一个组件?

3

我需要将Company组件中的selectedCoin状态发送到details.js组件中,我该如何使用context实现?

公司组件:

import React, { useState, useEffect } from "react";
import { Col, Image, Row } from "react-bootstrap";
import "./Company.scss";

// * api
import { getCoin } from "../services/api";

// *spinner
import Loader from "./Loader";

const Company = () => {
  const [selectedCoin, setSelectedCoin] = useState(null);
  const [coins, setCoins] = useState([]);

  useEffect(() => {
    const fetchAPI = async () => {
      const data = await getCoin();
      setCoins(data);
    };
    fetchAPI();
  }, []);

  const coinId = () => {
    console.log(selectedCoin);
  };

  coinId();

  return (
    <>
      {coins.length > 0 ? (
        coins.map((coin) => (
          <Row
            className={
              selectedCoin === coin.id
                ? "p-2 pe-3 border-top d-flex align-items-center company-list-single-active"
                : "p-2 border-top d-flex align-items-center company-list-single"
            }
            onClick={() => {
              setSelectedCoin(coin.id);
              // console.log(coin.id);
              // console.log(coin.name);
            }}
            key={coin.id}
          >
            <Col xxl="2" xl="2" lg="3" md="3" sm="2" xs="2">
              <Image
                src={coin.image}
                alt={coin.name}
                className="coin-image mx-2"
                fluid
              />
            </Col>
            <Col>
              <span>{coin.name}</span>
            </Col>
          </Row>
        ))
      ) : (
        <Loader />
      )}
    </>
  );
};
export default Company;

详细组件:

import React, { useState, useEffect } from "react";
import axios from "axios";

const Details = () => {
  const [data, setData] = useState({
    name: "",
    id: "",
  });

  const apiDetails = async () => {
    await axios
      .get(`https://api.coingecko.com/api/v3/coins/${"ethereum"}`)
      .then((r) => {
        // console.log(response);
        setData({
          name: r.data.name,
          id: r.data.id,
        });
        return setData;
      });
  };

  useEffect(() => {
    (async () => {
      const response = await apiDetails();
      setData({
        name: response.data.name,
        id: response.data.id,
      });
    })();
  }, []);

  return (
    <div>
      <h1>{data.name}</h1>
      <h1>{data.id}</h1>
    </div>
  );
};

export default Details;

Related - Jared Smith
2个回答

4

嗯,看起来你只对代码感兴趣,对吧? 那我就把代码放在这里。

随意移动代码并使用符合你理解的语法。


CoinsContext.js

import React, { createContext, useContext, useState, useEffect } from "react";
import { getCoin } from "@api";

const CoinsContext = createContext({});

export const CoinsContextProvider = ({ children }) => {
  const [selectedCoin, setSelectedCoin] = useState(null);
  const [coins, setCoins] = useState([]);

  useEffect(() => {
    const fetchAPI = async () => {
      const data = await getCoin();
      setCoins(data);
    };
    fetchAPI();
  }, []);

  return (
    <CoinsContext.Provider value={{ selectedCoin, setSelectedCoin, coins }}>
      {children}
    </CoinsContext.Provider>
  );
};

export const useCoins = () => useContext(CoinsContext);

如果您想在Detail.jsCompany.js中使用上述上下文,您必须将页面包装起来,这适用于所有页面。 通常我们会包装整个App,这意味着整个应用程序都可以使用它。然而,有一个缺点。每当上下文中的状态更新时,所有被该上下文包装的页面也将更新,因此您必须评估您的应用程序并选择最适合您的选项。
话虽如此,包装整个应用程序看起来像这样:

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

import { CoinsContextProvider } from "./CoinsContext";

ReactDOM.render(
  <React.StrictMode>
    <CoinsContextProvider>
      <App />
    </CoinsContextProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

现在我们已经设置好了CoinsContext,可以在您的组件上使用它。

Company.js

import React from "react";
import { Col, Image, Row } from "react-bootstrap";
import "./Company.scss";

// *spinner
import Loader from "./Loader";
import { useCoins } from "./CoinsContext";

const Company = () => {
  const { coins, selectedCoin, setSelectedCoin } = useCoins();

  return (
    <>
      {coins.length > 0 ? (
        coins.map((coin) => (
          <Row
            className={
              selectedCoin === coin.id
                ? "p-2 pe-3 border-top d-flex align-items-center company-list-single-active"
                : "p-2 border-top d-flex align-items-center company-list-single"
            }
            onClick={() => {
              setSelectedCoin(coin.id);
              // console.log(coin.id);
              // console.log(coin.name);
            }}
            key={coin.id}
          >
            <Col xxl="2" xl="2" lg="3" md="3" sm="2" xs="2">
              <Image
                src={coin.image}
                alt={coin.name}
                className="coin-image mx-2"
                fluid
              />
            </Col>
            <Col>
              <span>{coin.name}</span>
            </Col>
          </Row>
        ))
      ) : (
        <Loader />
      )}
    </>
  );
};
export default Company;

Details.js

import React, { useState, useEffect } from "react";
import axios from "axios";

import { useCoins } from "./CoinsContext";

const Details = () => {
  const { selectedCoin, coins, setSelectedCoin } = useCoins();
  
  const [data, setData] = useState({
    name: "",
    id: "",
  });

  // I recommend you to move this to the context as well
  const apiDetails = async () => {
    await axios
      .get(`https://api.coingecko.com/api/v3/coins/${"ethereum"}`)
      .then((r) => {
        // console.log(response);
        setData({
          name: r.data.name,
          id: r.data.id,
        });
        return setData;
      });
  };

  useEffect(() => {
    (async () => {
      const response = await apiDetails();
      setData({
        name: response.data.name,
        id: response.data.id,
      });
    })();
  }, []);

  return (
    <div>
      <h1>{data.name}</h1>
      <h1>{data.id}</h1>
    </div>
  );
};

export default Details;

我们完成了! 现在你不仅在组件之间共享状态(selectedCoin),而且还将获取货币的业务逻辑集中在上下文中,这 总体来说 是正确的做法。


感谢您的请求。 - Mohammad Mohseni

2
你只需要创建一个上下文的包装器。这个包装器只是一个组件,它的状态将作为你的上下文值传递,以允许你在任何地方编辑它。
以下是一个简单的示例,演示了如何实现上下文来在组件之间共享数据:
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';

const MyContext = React.createContext();
const MyContextProvider = (props) => {
  const [data, setData] = React.useState('Initial value');

  return (
    <MyContext.Provider value={{ data, setData }}>
      {props.children}
    </MyContext.Provider>
  );
};

const App = () => {
  return (
    <MyContextProvider>
      <Component1 />
      <hr />
      <Component2 />
    </MyContextProvider>
  );
};

const Component1 = () => {
  const { data, setData } = React.useContext(MyContext);
  return (
    <>
      [component 1] data = {data}
      <br />
      <button onClick={() => setData('data written from component 1')}>
        Update context
      </button>
    </>
  );
};

const Component2 = () => {
  const { data, setData } = React.useContext(MyContext);
  return (
    <>
      [component 2] data = {data}
      <br />
      <button onClick={() => setData('data written from component 2')}>
        Update context
      </button>
    </>
  );
};

render(<App />, document.getElementById('root'));

这里是Stackblitz


谢谢你,我正在阅读... - Mohammad Mohseni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接