I need to send selectedCoin
state from Company
to details.js
How do I do this with context
?
company component:
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;
details components:
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;
Well, looks like you're just interested on the code, right? so I'll just drop the code in here.
Always feel free to move code around and use the syntax that makes sense to you.
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);
If you want to use the above context on Detail.js
and Company.js
, you must wrap up the pages with it, that applies to all pages.
Usually we wrap the entire App
, which means the entire app can use it. There is however a down side. Every time a state inside a context updates, all the pages that are wrapped by that context will update as well, therefore you must assess your application and choose what's best for you.
That said, wrapping the whole app looks 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 that we have 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: "",
});
// 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;
And we're done!
Now you are not just sharing a state (selectedCoin
) between your components, but you're also centralizing the fetch coins business logic in your context, which overall is the right thing to do.