我有一个React父组件,用于保存整个应用程序的状态。我想将一个函数传递给子组件,以便在该子组件中单击按钮时,它将更改父组件的状态。现在,我可以在一层上执行此操作,但是,当我尝试将函数向下传递到另一层(因此,子组件向下传递作为道具接收到的函数)时,我的应用程序将发生以下错误:>
TypeError: Cannot read property 'props' of undefined
是否可以将此功能向下传递到多层?
在最低层,我没有设置构造函数,因为我认为只需要我需要在子组件中初始化状态,对吗?
我在下面详细介绍了代码的相关部分:
父母:
class App extends Component {
constructor() {
super();
this.changeDisplay = this.changeDisplay.bind(this)
this.handleAddTicket = this.handleAddTicket.bind(this)
this.handleDeleteTicket = this.handleDeleteTicket.bind(this)
this.state = {...}
...
}
handleDeleteTicket(data){
console.log(data)
} ....
第一个孩子
class Board extends React.Component {
return (
<Container>
<Row>
<Col sm={4}>
<Todo tasks={todoTasks} deleteTicket={this.props.deleteTicket}/>
</Col>
</Row>
</Container>
)
}
第二个孩子:
class Todo extends React.Component {
render() {
todoTicketsAr = this.props.tasks.map(function (obj, i) {
return <Ticket key={i} data={obj} deleteTicket={this.props.deleteTicket}></Ticket>
})
}
return (
<div>
<h2>To do:</h2>
{todoTicketsAr}
</div>
)
}
所以我要在父级上绑定它,对吗?
答案 0 :(得分:0)
唯一会发生的时间是因为this
不再正确绑定。我可以给出的一种常见情况是:
这将引发错误
class App extends Component {
someClickHandler() {
/**
* This line will throw an error onClick
* of the button because `this` is not bound to the right thing.
* If you log out `this` you'll probably see the click event object.
*/
console.log(this.state);
}
render() {
return (
<button onClick={this.someHandler}>Random button</button
)
}
}
要正确绑定this
,您必须执行任一操作
<button onClick={() => this.someHandler()}>Random button</button>
// or
<button onClick={this.someHandler.bind(this)}>Random button</button>
答案 1 :(得分:0)
这里是如何使用prop钻探和上下文API进行操作的示例。我将使用Context API示例,因为当您需要在不同组件中使用状态的不同部分时,无需保持prop钻探。
如果您想了解该方法的有效性并比较这两种解决方案,我还提供了一个道具钻探示例。
const Global = React.createContext({});
class Store extends React.Component {
static Consumer = Global.Consumer;
state = {
value: 'bacon',
};
changeValue = (value) => this.setState({ value });
render() {
const { value } = this.state;
const { changeValue } = this;
return (
<Global.Provider value={{
value,
changeValue,
}}>
{this.props.children}
</Global.Provider>
)
}
}
class Child extends React.Component {
state = {
text: '',
};
handleChange = (evt) => this.setState({ text: evt.target.value });
render() {
const { text } = this.state;
const { handleChange } = this;
return (
<Store.Consumer>
{({ value, changeValue }) => (
<div>
<h3>Value is {value}</h3>
<h5>Type a new value and submit</h5>
<input value={text} onChange={handleChange} />
<button onClick={() => changeValue(text)}>Submit</button>
</div>
)}
</Store.Consumer>
)
}
}
const Layout = () => (
<div>
<h5>An example component that is not exposed to context</h5>
<Child/>
</div>
)
const Main = () => (
<Store>
<h2>React Context API example</h2>
<Layout/>
</Store>
);
ReactDOM.render(<Main/>, document.body);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
const ChildOfChild = ({ toggleDisplay }) => (
<div>
<button onClick={toggleDisplay}>Toggle in Child of Child</button>
</div>
);
const Child = ({ toggleDisplay }) => (
<div>
<button onClick={toggleDisplay}>Toggle in Child</button>
<ChildOfChild toggleDisplay={toggleDisplay} />
</div>
);
class Main extends React.Component {
state = {
display: true,
};
toggleDisplay = () => {
this.setState((prevState) => ({
display: !prevState.display,
}));
};
render() {
const { toggleDisplay } = this;
return (
<div>
<h2>React Prop drilling Example</h2>
<pre>{this.state.display.toString()}</pre>
<button onClick={this.toggleDisplay}>Parent</button>
<Child toggleDisplay={toggleDisplay} />
</div>
);
}
}
ReactDOM.render(
<Main/>,
document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>