React js从父组件更改子组件的状态
Posted
技术标签:
【中文标题】React js从父组件更改子组件的状态【英文标题】:React js change child component's state from parent component 【发布时间】:2016-12-26 18:32:09 【问题描述】:我有两个组件: 我要更改子组件状态的父组件:
class ParentComponent extends Component
toggleChildMenu()
?????????
render()
return (
<div>
<button onClick=toggleChildMenu.bind(this)>
Toggle Menu from Parent
</button>
<ChildComponent />
</div>
);
和子组件:
class ChildComponent extends Component
constructor(props)
super(props);
this.state =
open: false;
toggleMenu()
this.setState(
open: !this.state.open
);
render()
return (
<Drawer open=this.state.open/>
);
我需要在父组件中更改子组件的open状态,或者在单击父组件中的按钮时从父组件调用子组件的toggleMenu()? p>
【问题讨论】:
也许你可以在父母中持有一个孩子的引用,并明确改变孩子的状态,见doc 【参考方案1】:状态应该在父组件中管理。您可以通过添加属性将open
值传递给子组件。
class ParentComponent extends Component
constructor(props)
super(props);
this.state =
open: false
;
this.toggleChildMenu = this.toggleChildMenu.bind(this);
toggleChildMenu()
this.setState(state => (
open: !state.open
));
render()
return (
<div>
<button onClick=this.toggleChildMenu>
Toggle Menu from Parent
</button>
<ChildComponent open=this.state.open />
</div>
);
class ChildComponent extends Component
render()
return (
<Drawer open=this.props.open/>
);
【讨论】:
是的,这基本上就是 react-classnames 包所做的,但它也允许您始终应用一组类名,并有条件地应用其他类名。像这样:classNames( foo: true, bar: this.props.open );
// => 'foo' 当 this.props.open = false 和 'foo bar' 当 this.props.open = true 时。
如何改变子组件的打开状态?
可以给子组件<ChildComponent open=this.state.open toggle=this.toggleChildMenu.bind(this) />
添加属性toggle
,在子组件中调用this.props.toggle()
我不明白,只要在声明ChildComponent
时指定了这个属性就可以在子组件中任意调用它-> <ChildComponent toggle=this.toggleChildMenu.bind(this) />
通过这种方式,整个父组件正在重新渲染,从而降低了效率。你能告诉我只有子组件会更新其状态或道具(意味着重新渲染)而不重新渲染父组件的任何方式吗?【参考方案2】:
父组件可以管理子状态,将 prop 传递给子组件,子组件使用 componentWillReceiveProps 将此 prop 转换为状态。
class ParentComponent extends Component
state = drawerOpen: false
toggleChildMenu = () =>
this.setState( drawerOpen: !this.state.drawerOpen )
render()
return (
<div>
<button onClick=this.toggleChildMenu>Toggle Menu from Parent</button>
<ChildComponent drawerOpen=this.state.drawerOpen />
</div>
)
class ChildComponent extends Component
constructor(props)
super(props)
this.state =
open: false
componentWillReceiveProps(props)
this.setState( open: props.drawerOpen )
toggleMenu()
this.setState(
open: !this.state.open
)
render()
return <Drawer open=this.state.open />
【讨论】:
在反应 16 中使用 getDerivedStateFromProps @FadiAboMsalam 我正在使用带有 @Types/react 版本 16.7.18 的 react 版本 16.7.0。至少在 TypeScript 方面似乎没有getDerivedStateFromProps()
。但是,Miguel 建议使用 componentWillReceiveProps(props)
的答案是可用的,并且在我的环境中就像一个魅力。
在这种情况下,子组件内部的 toggleMenu() 状态变化将如何到达父组件?想象一下我关闭了抽屉,父组件怎么知道它已经关闭了?【参考方案3】:
以上答案对我来说部分正确,但在我的场景中,我想将值设置为状态,因为我已使用该值来显示/切换模式。所以我像下面这样使用过。希望它会对某人有所帮助。
class Child extends React.Component
state =
visible:false
;
handleCancel = (e) =>
e.preventDefault();
this.setState( visible: false );
;
componentDidMount()
this.props.onRef(this)
componentWillUnmount()
this.props.onRef(undefined)
method()
this.setState( visible: true );
render()
return (<Modal title="My title?" visible=this.state.visible onCancel=this.handleCancel>
"Content"
</Modal>)
class Parent extends React.Component
onClick = () =>
this.child.method() // do stuff
render()
return (
<div>
<Child onRef=ref => (this.child = ref) />
<button onClick=this.onClick>Child.method()</button>
</div>
);
参考 - https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542
【讨论】:
这就是我想要的,但我想知道为什么不直接使用 react refs?见doc onRef 属性有什么作用? 这实际上是 react 中不鼓励使用的模式,因为它会反转信息流。如果 react 有一个 Zen,它是 数据向下,动作向上。这就是让 React 应用程序如此易于推理的概念。命令式句柄可能很有用,但应谨慎使用且经过深思熟虑。它们不应该是例如的首选解决方案。切换可见性。【参考方案4】:您可以使用createRef
从父组件更改子组件的状态。以下是所有步骤。
-
创建一个方法来更改子组件中的状态。
使用
React.createRef()
为父组件中的子组件创建引用。
使用ref=
将引用附加到子组件。
使用this.yor-reference.current.method
调用子组件方法。
父组件
class ParentComponent extends Component
constructor()
this.changeChild=React.createRef()
render()
return (
<div>
<button onClick=this.changeChild.current.toggleMenu()>
Toggle Menu from Parent
</button>
<ChildComponent ref=this.changeChild />
</div>
);
子组件
class ChildComponent extends Component
constructor(props)
super(props);
this.state =
open: false;
toggleMenu=() =>
this.setState(
open: !this.state.open
);
render()
return (
<Drawer open=this.state.open/>
);
【讨论】:
这是我找到的最佳答案,因为它不会重新渲染父组件。这是更快更好的做法! 是的,这实际上也是满足我需求的最佳答案。这很干净,我们应该赞成这个答案。 在父级上,我不得不使用处理程序方法而不是直接调用子级。然后它起作用了。【参考方案5】:您可以从父组件发送一个 prop 并在子组件中使用它,这样您就可以根据发送的 prop 更改来更改子组件的状态,您可以在子组件中使用 getDerivedStateFromProps 来处理这个问题。
【讨论】:
【参考方案6】:如果您使用的是功能组件。您可以通过以下方式实现:
const ParentComponent = () =>
const [isOpen, setIsOpen] = useState(false)
toggleChildMenu()
setIsOpen(prevValue => !prevValue)
return (
<div>
<button onClick=toggleChildMenu>
Toggle Menu from Parent
</button>
<Child open=isOpen />
</div>
);
const Child = (open) =>
return (
<Drawer open=open/>
);
【讨论】:
以上是关于React js从父组件更改子组件的状态的主要内容,如果未能解决你的问题,请参考以下文章
在 React.js 的父组件中使用 react-router 时,如何使用 react context API 将数据从父组件传递到子组件?