我的结构如下所示:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件 3 应根据组件 5 的状态显示一些数据。
由于 props 是不可变的,我不能简单地将其状态保存在 Component 1 中并转发它,对吗?是的,我已经阅读了 Redux,但我不想使用它。我希望可以通过反应来解决它。我错了吗?
<MyChildComponent setState={(s,c)=>{this.setState(s, c)}} />
如果您要使用此 hack,请确保您支持回调。
this.setState(p)
周围有大括号?我在没有它们的情况下尝试过,它似乎可以工作(我对 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}/ >
}
}
这样,孩子可以通过调用道具传递的函数来更新父母的状态。
但是您将不得不重新考虑组件的结构,因为据我了解,组件 5 和 3 不相关。
一种可能的解决方案是将它们包装在更高级别的组件中,该组件将包含组件 1 和 3 的状态。该组件将通过 props 设置较低级别的状态。
这是使用新的 useState
挂钩的方法。
方法 - 将状态更改器函数作为道具传递给子组件,然后对函数执行任何操作:
import React, {useState} from 'react';
const ParentComponent = () => {
const[state, setState]=useState('');
return(
<ChildComponent stateChanger={setState} />
)
}
const ChildComponent = ({stateChanger, ...rest}) => {
return(
<button onClick={() => stateChanger('New data')}></button>
)
}
我找到了以下工作解决方案,将 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")
);
}
<ChildB handleToUpdate = {handleToUpdate.bind(this)} />
为什么要再次绑定?
this
时, this
指的是父级的状态而不是子级的状态。这是最好的关闭!
我要感谢最受好评的答案,因为它让我了解了我自己的问题,基本上是它与箭头函数的变化并从子组件传递参数:
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')}/ >
}
}
希望它可以帮助某人。
this
指的是父级的上下文(即 Parent
类)。
我喜欢关于传递函数的答案。这是一个非常方便的技术。
另一方面,您也可以像 Flux 那样使用 pub/sub 或使用变体调度程序来实现此目的。理论超级简单。让组件 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)。如果这对您更有意义,您可以很容易地将其适应传统的 pub/sub(例如,使用事件中的 EventEmitter 或其他版本)。
我找到了以下工作解决方案,将 onClick 函数参数从子组件传递给带有参数的父组件:
父类:
class Parent extends React.Component {
constructor(props) {
super(props)
// Bind the this context to the handler function
this.handler = this.handler.bind(this);
// Set some state
this.state = {
messageShown: false
};
}
// This method will be sent to the child component
handler(param1) {
console.log(param1);
this.setState({
messageShown: true
});
}
// Render the child component and set the action property with the handler as value
render() {
return <Child action={this.handler} />
}}
儿童班:
class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component */}
<Button onClick={this.props.action.bind(this,param1)} />
</div>
)
} }
param1
只是显示在控制台上而不是分配它总是分配 true
每当您需要在任何级别的孩子与父母之间进行交流时,最好利用上下文。在父组件中定义可以被子组件调用的上下文,例如:
在父组件中,在您的案例组件 3 中,
static childContextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
getChildContext() {
return {
parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
};
}
parentMethod(parameter_from_child){
// Update the state with parameter_from_child
}
现在在子组件(在您的情况下为组件 5)中,只需告诉该组件它想要使用其父组件的上下文。
static contextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
render() {
return(
<TouchableHighlight
onPress = {() => this.context.parentMethod(new_state_value)}
underlayColor='gray' >
<Text> update state in parent component </Text>
</TouchableHighlight>
)}
您可以在 this GitHub repository 中找到演示项目。
似乎我们只能将数据从父级传递给子级,因为 React 提倡单向数据流,但是为了让父级在其“子组件”发生某些事情时自行更新,我们通常使用所谓的“回调函数”。
我们将父级中定义的函数作为“道具”传递给子级,并从子级调用该函数,在父组件中触发它。
class Parent extends React.Component {
handler = (Value_Passed_From_SubChild) => {
console.log("Parent got triggered when a grandchild button was clicked");
console.log("Parent->Child->SubChild");
console.log(Value_Passed_From_SubChild);
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <SubChild handler = {this.props.handler}/ >
}
}
class SubChild extends React.Component {
constructor(props){
super(props);
this.state = {
somethingImp : [1,2,3,4]
}
}
render() {
return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
}
}
React.render(<Parent />,document.getElementById('app'));
HTML
----
<div id="app"></div>
在此示例中,我们可以通过将函数传递给其直接子项来使数据从子子→子→父传递。
我已经多次使用此页面中评价最高的答案,但是在学习 React 时,我找到了一种更好的方法来做到这一点,无需绑定,也无需在 props 中使用内联函数。
看看这里:
class Parent extends React.Component {
constructor() {
super();
this.state = {
someVar: value
}
}
handleChange = (someValue) => {
this.setState({someVar: someValue})
}
render() {
return <Child handler={this.handleChange} />
}
}
export const Child = ({handler}) => {
return <Button onClick={handler} />
}
关键在于箭头函数:
handleChange = (someValue) => {
this.setState({someVar: someValue})
}
您可以阅读更多here。
我们可以创建 ParentComponent 并使用 handleInputChange 方法来更新 ParentComponent 的状态。导入 ChildComponent,我们将两个 props 从父组件传递给子组件,即 handleInputChange 函数和计数。
import React, { Component } from 'react';
import ChildComponent from './ChildComponent';
class ParentComponent extends Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
count: '',
};
}
handleInputChange(e) {
const { value, name } = e.target;
this.setState({ [name]: value });
}
render() {
const { count } = this.state;
return (
<ChildComponent count={count} handleInputChange={this.handleInputChange} />
);
}
}
现在我们创建 ChildComponent 文件并将其保存为 ChildComponent.jsx。该组件是无状态的,因为子组件没有状态。我们使用 prop-types 库进行 props 类型检查。
import React from 'react';
import { func, number } from 'prop-types';
const ChildComponent = ({ handleInputChange, count }) => (
<input onChange={handleInputChange} value={count} name="count" />
);
ChildComponent.propTypes = {
count: number,
handleInputChange: func.isRequired,
};
ChildComponent.defaultProps = {
count: 0,
};
export default ChildComponent;
如果要更新父组件,
class ParentComponent extends React.Component {
constructor(props){
super(props);
this.state = {
page: 0
}
}
handler(val){
console.log(val) // 1
}
render(){
return (
<ChildComponent onChange={this.handler} />
)
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1
};
}
someMethod = (page) => {
this.setState({ page: page });
this.props.onChange(page)
}
render() {
return (
<Button
onClick={() => this.someMethod()}
> Click
</Button>
)
}
}
这里的 onChange 是一个属性,其实例绑定了“处理程序”方法。我们将方法处理程序传递给 Child 类组件,以通过其 props 参数中的 onChange 属性接收。
onChange 属性将在 props 对象中设置,如下所示:
props = {
onChange: this.handler
}
并传递给子组件。
所以子组件可以像这个props.onChange一样访问props对象中name的值。
这是通过使用渲染道具完成的。
现在,子组件有一个“Click”按钮,其中设置了一个 onclick 事件,以调用通过其 props 参数对象中的 onChange 传递给它的处理程序方法。所以现在子类中的 this.props.onChange 持有父类中的输出方法。
参考和出处: Bits and Pieces
如果同样的场景没有在任何地方传播,你可以使用 React 的上下文,特别是如果你不想引入状态管理库引入的所有开销。另外,它更容易学习。但小心点;你可能会过度使用它并开始编写糟糕的代码。基本上,您定义了一个 Container 组件(它将为您保存并保留该状态),使所有组件都对向/从其子级(不一定是直接子级)写入/读取该数据块感兴趣。
你也可以正确地使用一个普通的 React。
<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />
将 doSomethingAbout5 传递给组件 1:
<Component1>
<Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
<Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>
如果这是一个常见问题,您应该开始考虑将应用程序的整个状态转移到其他地方。您有几个选择,最常见的是:
还原
通量
基本上,不是在组件中管理应用程序状态,而是在发生某些事情时发送命令来更新状态。组件也从这个容器中提取状态,因此所有数据都是集中的。这并不意味着您不能再使用本地状态,但这是一个更高级的主题。
我们可以通过将函数作为 props 传递给子组件来设置子组件的父状态,如下所示:
class Parent extends React.Component{
state = { term : ''}
onInputChange = (event) => {
this.setState({term: event.target.value});
}
onFormSubmit = (event) => {
event.preventDefault();
this.props.onFormSubmit(this.state.term);
}
render(){
return (
<Child onInputChange={this.onInputChange} onFormSubmit=
{this.onFormSubmit} />
)
}
}
class Child extends React.Component{
render(){
return (
<div className="search-bar ui segment">
<form className="ui form" onSubmit={this.props.onFormSubmit}>
<div class="field">
<label>Search Video</label>
<input type="text" value={this.state.term} onChange=
{this.props.onInputChange} />
</div>
</form>
</div>
)
}
}
这样,孩子将更新父状态 onInputChange 和 onFormSubmit 是从父母传递的道具。这可以从子事件侦听器中调用,因此状态将在那里更新。
这是一个简短的片段,用于获取两种绑定数据的方式。
计数器显示来自父级的值并从子级更新
class Parent 扩展 React.Component { constructor(props) { super(props) this.handler = this.handler.bind(this) this.state = { count: 0 } } handler() { this.setState({ count: this .state.count + 1 }) } render() { return
这就是我这样做的方式:
type ParentProps = {}
type ParentState = { someValue: number }
class Parent extends React.Component<ParentProps, ParentState> {
constructor(props: ParentProps) {
super(props)
this.state = { someValue: 0 }
this.handleChange = this.handleChange.bind(this)
}
handleChange(value: number) {
this.setState({...this.state, someValue: value})
}
render() {
return <div>
<Child changeFunction={this.handleChange} defaultValue={this.state.someValue} />
<p>Value: {this.state.someValue}</p>
</div>
}
}
type ChildProps = { defaultValue: number, changeFunction: (value: number) => void}
type ChildState = { anotherValue: number }
class Child extends React.Component<ChildProps, ChildState> {
constructor(props: ChildProps) {
super(props)
this.state = { anotherValue: this.props.defaultValue }
this.handleChange = this.handleChange.bind(this)
}
handleChange(value: number) {
this.setState({...this.state, anotherValue: value})
this.props.changeFunction(value)
}
render() {
return <div>
<input onChange={event => this.handleChange(Number(event.target.value))} type='number' value={this.state.anotherValue}/>
</div>
}
}
根据您的问题,我了解您需要在组件 3 中显示一些基于组件 5 状态的条件数据。方法:
组件 3 的状态将保存一个变量来检查组件 5 的状态是否具有该数据 一个箭头函数将更改组件 3 的状态变量。使用 props 将箭头函数传递给组件 5。组件 5 有一个箭头函数,它将改变组件 3 的状态变量 组件 5 的箭头函数在加载自身时调用
Class Component3 extends React.Component { state = { someData = true } checkForData = (result) => { this.setState({someData : result}) } render() { if(this.state.someData) { return(
只需通过 props 将父组件的 setState 函数传递给子组件。
function ParentComp() {
const [searchValue, setSearchValue] = useState("");
return <SearchBox setSearchValue={setSearchValue} searchValue={searchValue} />;
}
然后在子组件中:
function SearchBox({ searchValue, setSearchValue }) {
return (
<input
id="search-post"
type="text"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="Search Blogs ..."
/>
)
}
处理来自子组件的点击的第二个示例:
// We've below function and component in parent component
const clickHandler = (val) => {
alert(`httpRequest sent. \nValue Received: ${val}`);
};
// JSX
<HttpRequest clickHandler={clickHandler} />
这就是您从父组件获取函数然后传递一个值并通过它触发 clickHandler
的方式。
function HttpRequest({ clickHandler }) {
const [content, setContent] = useState("initialState");
return (
<button onClick={() => clickHandler(content)}>
Send Request
</button>
);
}
export default HttpRequest;
要在孩子中设置父母的状态,您可以使用回调。
const Child = ({handleClick}) => (
<button on click={() => handleClick('some vale')}>change value</button>
)
const parent = () => {
const [value, setValue] = useState(null)
return <Child handleClick={setValue} />
}
在您的结构中,组件 1 和 3 似乎是兄弟。所以你有3个选择:
1-将状态放入它们的父级(不推荐用于4层父子级)。
2- 一起使用 useContext 和 useRducer(或 useState)。
3- 使用状态管理器,如 redux、mobx ...
这似乎对我有用
家长:
...
const [open, setOpen] = React.useState(false);
const handleDrawerClose = () => {
setOpen(false);
};
...
return (
<PrimaryNavigationAccordion
handleDrawerClose={handleDrawerClose}
/>
);
孩子:
...
export default function PrimaryNavigationAccordion({
props,
handleDrawerClose,
})
...
<Link
to={menuItem.url}
component={RouterLink}
color="inherit"
underline="hover"
onClick={() => handleDrawerClose()}
>
{menuItem.label}
</Link>
您可以通过将父级的引用传递给子级来做到这一点,如下所示:
在 A.js 中使用方法 updateAState 在 A.js 中具有父组件 A 在 B.js 中具有子组件 B 在 C.js 中呈现 的包装器函数 在 C.js 中您可以使用 useRef 如下:
导入反应,{ useRef } 从“反应”;导出默认函数 C() { const parentARef = useRef(); const handleChildBClick = () => parentARef.current.updateAState();返回( ); }
指导参考:https://stackoverflow.com/a/56496607/1770571
父组件
function Parent() {
const [value, setValue] = React.useState("");
function handleChange(newValue) {
setValue(newValue);
}
// We pass a callback to Child
return <Child value={value} onChange={handleChange} />;
}
子组件
function Child(props) {
function handleChange(event) {
// Here, we invoke the callback with the new value
props.onChange(event.target.value);
}
return <input value={props.value} onChange={handleChange} />
}
<Footer
action={()=>this.setState({showChart: true})}
/>
<footer className="row">
<button type="button" onClick={this.props.action}>Edit</button>
{console.log(this.props)}
</footer>
Try this example to write inline setState, it avoids creating another function.
this.handler = this.handler.bind(this)
,则handler
函数内的this
将引用函数闭包,而不是类。如果不想在构造函数中绑定所有函数,还有另外两种方法可以使用箭头函数来处理这个问题。您可以将点击处理程序编写为onClick={()=> this.setState(...)}
,或者您可以将属性初始化程序与箭头函数一起使用,如此处 babeljs.io/blog/2015/06/07/react-on-es6-plus 在“箭头函数”下所述