我的结构如下:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件 3 应根据组件 5 的状态显示一些数据。
由于 props 是不可变的,我不能简单地将它的状态保存在组件 1 中并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望可以通过react来解决它。我错了吗?
我的结构如下:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件 3 应根据组件 5 的状态显示一些数据。
由于 props 是不可变的,我不能简单地将它的状态保存在组件 1 中并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望可以通过react来解决它。我错了吗?
对于子父通信,您应该传递一个函数来设置从父到子的状态,就像这样
class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
}
handler() {
this.setState({
someVar: 'some value'
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}
通过这种方式,子进程可以通过调用通过 props 传递的函数来更新父进程的状态。
但是您必须重新考虑组件的结构,因为据我了解,组件 5 和 3 不相关。
一种可能的解决方案是将它们包装在更高级别的组件中,该组件将包含组件 1 和 3 的状态。该组件将通过 props 设置较低级别的状态。
我发现以下工作解决方案将 onClick 函数参数从子组件传递给父组件:
传递方法()的版本
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div><button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
var handleToUpdate = this.handleToUpdate.bind(this);
var arg1 = '';
}
handleToUpdate(someArg){
alert('We pass argument from Child to Parent: ' + someArg);
this.setState({arg1:someArg});
}
render() {
var handleToUpdate = this.handleToUpdate;
return (<div>
<ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
传递箭头函数的版本
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div>
<button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
}
handleToUpdate = (someArg) => {
alert('We pass argument from Child to Parent: ' + someArg);
}
render() {
return (<div>
<ChildB handleToUpdate = {this.handleToUpdate} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
这就是我们如何使用新useState
钩子来做到这一点。方法 - 将状态更改器函数作为props传递给子组件,并对该函数执行任何您想做的事情
import React, {useState} from 'react';
const ParentComponent = () => {
const[state, setState]=useState('');
return(
<ChildConmponent stateChanger={setState} />
)
}
const ChildConmponent = ({stateChanger, ...rest}) => {
return(
<button onClick={() => stateChanger('New data')}></button>
)
}
我要感谢最受好评的答案给了我我自己的问题的想法,基本上是它与箭头函数的变化和从子组件传递参数:
class Parent extends React.Component {
constructor(props) {
super(props)
// without bind, replaced by arrow func below
}
handler = (val) => {
this.setState({
someVar: val
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {() => this.props.handler('the passing value')}/ >
}
}
希望它可以帮助某人。
我喜欢关于传递函数的答案。这是一个非常方便的技术。
另一方面,您也可以使用 pub/sub 或使用变体、调度程序来实现这一点,就像Flux一样。理论超级简单。让组件 5 发送组件 3 正在侦听的消息。然后组件 3 更新其触发重新渲染的状态。这需要有状态的组件,根据您的观点,它可能是也可能不是反模式。我个人反对他们,宁愿其他东西从上到下监听调度和更改状态(Redux 这样做,但它增加了额外的术语)。
import { Dispatcher } from 'flux'
import { Component } from 'React'
const dispatcher = new Dispatcher()
// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
state = {
text: 'foo'
}
componentDidMount() {
dispatcher.register( dispatch => {
if ( dispatch.type === 'change' ) {
this.setState({ text: 'bar' })
}
}
}
render() {
return <h1>{ this.state.text }</h1>
}
}
// Click handler
const onClick = event => {
dispatcher.dispatch({
type: 'change'
})
}
// Component 5 in your example
const StatelessChild = props => {
return <button onClick={ onClick }>Click me</button>
}
与 Flux 捆绑的调度程序非常简单。它只是注册回调并在任何调度发生时调用它们,传递调度上的内容(在上面的简洁示例中payload
,调度没有,只是一个消息 ID)。如果这对您更有意义,您可以非常轻松地将其调整为传统的发布/订阅(例如,使用来自事件的 EventEmitter 或其他版本)。