I was playing around with useContext in a class component. I've created a simple react (nextjs) application with one button that call a function in the context that update the state and therefore re-render the home component.
import { useContext } from "react";
import { UserContext } from "../provider/TestProvider";
export default function Home() {
let [contex] = useContext(UserContext);
return (
<>
<button onClick={() => contex.addOne()}>Add 1</button>
{contex.state.count.map((e) => (
<div key={Math.random()}> {e} </div>
))}
</>
);
}
import { createContext, Component } from "react";
export const UserContext = createContext();
export default class TestProvider extends Component {
state = {count: []};
constructor(props) {
super(props);
this.props = props;
}
addOne() {
let oldState = [...this.state.count];
oldState.push("test");
this.setState({ count: oldState });
}
render() {
return (
<UserContext.Provider value={[this]}>
{this.props.children}
</UserContext.Provider>
);
}
}
Note: The provider it's wrapped to the entire application, inside _app.js
this is working fine, however I was wondering why I'm forced to pass this
inside an array ( value={[this]}
)? When I tried to pass only this ( value={this}
) [and modify the context let contex = useContext(UserContext)
], the Home function doesn't react anymore on the change of the state, and therefore no rerender.
From my knowledge of programming both options should behave exactly the same.
What is happening here?
You are only "forced" to pass the context value as value={[this]}
because that is how you are accessing it in the consumer.
let [contex] = useContext(UserContext);
Here you are using array destructuring assignment to get the context value out of the array and accessible.
contex.state.count
In other words, this.state.count
and contex.state.count
are the same thing.
It rather more that you are forced to consume it from an array because that is how it was provided: value={[this]}
.
Instead of passing the entire this
object of the root parent class component it would be better to pass only what you need to, like only the count
state and the addOne
callback function.
Example:
export const UserContext = createContext({
addOne: () => {},
count: [],
});
export default class TestProvider extends Component {
state = { count: [] };
addOne = () => {
this.setState(prevState => ({
count: [...prevState.count, "test"];
}));
}
render() {
const { children } = this.props;
const { count } = this.state;
return (
<UserContext.Provider value={{ addOne, count }}> // provided as object
{children}
</UserContext.Provider>
);
}
}
...
import { useContext } from "react";
import { UserContext } from "../provider/TestProvider";
export default function Home() {
const { addOne, count } = useContext(UserContext); // object destructuring assignment
return (
<>
<button onClick={addOne}>Add 1</button>
{count.map((e) => (
<div key={e}>{e}</div>
))}
</>
);
}
The main takeaway here though should be that however you are consuming the context value should match how you are providing it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.