问题
I am testing out React's Context API and have successfully passed down my state items and a method to a Consumer component. However, when I add some conditional logic to the method I am losing reference to the state object items. I get a "Cannot read property 'color' of undefined" error. How do I reference by color key in that state object so I can run the logic? Am I able to do this in the Provider component or am I only able to do this logic in the Consumer component?
Provider Container File - ProviderComp.js
class ProviderComp extends Component{
state={
name: "Gary",
age: 20,
color: "Red",
changeMind: function(){
if(this.color === "Red"){
document.getElementById("root").style.background="blue";
document.getElementById("root").style.color="white";
this.setState({
name: "Tony",
age: 35,
color: "Blue"
})
}
if(this.color === "Blue"){
document.getElementById("root").style.background="red";
document.getElementById("root").style.color="black";
this.setState({
name: "Gary",
age: 20,
color: "Red"
})
}
}
}
render(){
return(
<UserInfo.Provider value={{state:this.state}}>
{this.props.children}
</UserInfo.Provider>
)
}
}
export default ProviderComp;
Consumer Component - ConsumerComp.js
import React, {Component} from "react";
import UserInfo from "./ContextData";
class ConsumerComp extends Component{
render(){
return(
<UserInfo.Consumer>
{(context)=>(
<React.Fragment>
<p>My Name Is: {context.state.name}</p>
<p>My Age Is: {context.state.age}</p>
<p>My Favorite Color Is: {context.state.color}</p>
<button onClick={context.state.changeMind}>Changed My Mind</button>
</React.Fragment>
)}
</UserInfo.Consumer>
)
}
}
export default ConsumerComp;
回答1:
i think your approach is error prone.
better when you create function outside state, and then pass down to ConsumerComp
as a props, something like this:
class ProviderComp extends Component{
state={
name: "Gary",
age: 20,
color: "Red"}
constructor(props){
super(props);
this.changeMind=this.changeMind.bind.this;
}
changeMind(){
if(this.state.color === "Red"){
// ...///
this.setState({
//...
})
}
}
///
render(){
<UserInfo.Provider value={{state:this.state}}>
{React.Children.map(children, (child, index) =>
React.cloneElement(child,{changeMind: this.changeMind})
)}
</UserInfo.Provider>
}
}
回答2:
Thank you Chris. The issue is with the ES5 syntax. I needed to use a fat arrow syntax => to bind this to the component. This allowed me to access state in my logic. This is the working code. Note that with this process the context API allows one to skip sending props down multiple levels which is pretty cool.
import React, {Component} from "react";
import UserInfo from "./ContextData";
class ProviderComp extends Component{
state={
name: "Gary",
age: 20,
color: "Red",
changeMind: ()=>{
if(this.state.color === "Red"){
document.getElementById("root").style.background="blue";
document.getElementById("root").style.color="white";
this.setState({
name: "Tony",
age: 35,
color: "Blue"
})
}
if(this.state.color === "Blue"){
document.getElementById("root").style.background="red";
document.getElementById("root").style.color="black";
this.setState({
name: "Gary",
age: 20,
color: "Red"
})
}
}
}
render(){
return(
<UserInfo.Provider value={{state:this.state}}>
{this.props.children}
</UserInfo.Provider>
)
}
}
export default ProviderComp;
来源:https://stackoverflow.com/questions/51480718/react-context-api-how-to-get-reference-to-state-object-in-provider-for-a-condi