javascript - how to send data From one component to another components with context in react? - TagMerge
3how to send data From one component to another components with context in react?how to send data From one component to another components with context in react?

how to send data From one component to another components with context in react?

Asked 1 years ago
2
3 answers

You just need to create a wrapper of your context. this wrapper is just a component, and its state will be passed as values of your context to allow you to edit it wherever you want.

Here is a simple example of how you can implement your context to share data between components :

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'));

Here is the Stackblitz.

Source: link

1

Well, looks like you're just interested on the code right, so I'll just drop the code in here. Obviously, feels free to move code around and make sure you use the syntax that does make sense to you

This is the context

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);

To use it, you need to wrap up all the pages that are gonna use the context with it, for example, since you want Details.js and Company.js to use it, you will need to wrap both pages with it. I'll just wrap the entire App, which means the entire app can use it, but feel free to do what you want.

Would be something like this:

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")
);

Now we have the CoinsContext set up, we can use it on your components

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: "",
  });


  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;

And we're done! Now you are not just sharing selectedCoin between your components, but you're also putting all coins fetching logic in your context, which overall is the right thing to do

Source: link

0

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

function Toolbar(props) {
  // The Toolbar component must take an extra "theme" prop  // and pass it to the ThemedButton. This can become painful  // if every single button in the app needs to know the theme  // because it would have to be passed through all components.  return (
    <div>
      <ThemedButton theme={props.theme} />    </div>
  );
}

class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}
// Context lets us pass a value deep into the component tree// without explicitly threading it through every component.// Create a context for the current theme (with "light" as the default).const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    // Use a Provider to pass the current theme to the tree below.    // Any component can read it, no matter how deep it is.    // In this example, we're passing "dark" as the current value.    return (
      <ThemeContext.Provider value="dark">        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// A component in the middle doesn't have to// pass the theme down explicitly anymore.function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Assign a contextType to read the current theme context.  // React will find the closest theme Provider above and use its value.  // In this example, the current theme is "dark".  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;  }
}
For example, consider a Page component that passes a user and avatarSize prop several levels down so that deeply nested Link and Avatar components can read it:
<Page user={user} avatarSize={avatarSize} />
// ... which renders ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... which renders ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... which renders ...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>
One way to solve this issue without context is to pass down the Avatar component itself so that the intermediate components don’t need to know about the user or avatarSize props:
function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// Now, we have:
<Page user={user} avatarSize={avatarSize} />
// ... which renders ...
<PageLayout userLink={...} />
// ... which renders ...
<NavigationBar userLink={...} />
// ... which renders ...
{props.userLink}
You’re not limited to a single child for a component. You may pass multiple children, or even have multiple separate “slots” for children, as documented here:
function Page(props) {
  const user = props.user;
  const content = <Feed user={user} />;
  const topBar = (
    <NavigationBar>
      <Link href={user.permalink}>
        <Avatar user={user} size={props.avatarSize} />
      </Link>
    </NavigationBar>
  );
  return (
    <PageLayout
      topBar={topBar}
      content={content}
    />
  );
}

Source: link

Recent Questions on javascript

    Programming Languages