如何将数据从一个组件发送到另一个具有反应上下文的组件?
how to send data From one component to another components with context in react?
我需要将 selectedCoin
状态从 Company
发送到 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;
您只需要创建上下文的包装器。这个包装器只是一个组件,它的状态将作为上下文的值传递,以便您可以在任何需要的地方对其进行编辑。
这是一个简单的示例,说明如何实现上下文以在组件之间共享数据:
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.
嗯,看起来你只是对代码感兴趣,所以我就把代码放在这里。
显然,可以随意移动代码并确保使用对您有意义的语法
这是上下文
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);
要使用它,您需要将所有要使用它的上下文的页面包装起来,例如,因为您想要 Details.js 和 Company.js 使用它,您将需要用它包裹两页。
我只是把整个 App 包装起来,这意味着整个 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: "",
});
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,而且您还将所有硬币获取逻辑放在您的上下文中,总体而言这是正确的做法
我需要将 selectedCoin
状态从 Company
发送到 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;
您只需要创建上下文的包装器。这个包装器只是一个组件,它的状态将作为上下文的值传递,以便您可以在任何需要的地方对其进行编辑。
这是一个简单的示例,说明如何实现上下文以在组件之间共享数据:
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.
嗯,看起来你只是对代码感兴趣,所以我就把代码放在这里。 显然,可以随意移动代码并确保使用对您有意义的语法
这是上下文
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);
要使用它,您需要将所有要使用它的上下文的页面包装起来,例如,因为您想要 Details.js 和 Company.js 使用它,您将需要用它包裹两页。 我只是把整个 App 包装起来,这意味着整个 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: "",
});
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,而且您还将所有硬币获取逻辑放在您的上下文中,总体而言这是正确的做法