我的结构如下所示:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件3应该根据组件5的状态显示一些数据。
因为道具是不可变的,我不能简单地在组件1中保存它的状态并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望只用react就能解决这个问题。我错了吗?
我的结构如下所示:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件3应该根据组件5的状态显示一些数据。
因为道具是不可变的,我不能简单地在组件1中保存它的状态并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望只用react就能解决这个问题。我错了吗?
当前回答
你可以通过将父对象的引用传递给子对象来实现,如下所示:
在A.js中有一个带有updateAState方法的父组件a 在B.js中有一个子组件B 有一个包装器函数,在C.js中呈现< a ><B></B></ a > 在C.js中,你可以像下面这样使用useRef:
import React, {useRef} from " React "; 导出默认函数C() { const parentARef = useRef(); const handleChildBClick = () => parentARef.current.updateAState(); 回报( < ref = {parentARef} > < B onClick = {handleChildBClick} > < / B > < / > ); }
指南参考:https://stackoverflow.com/a/56496607/1770571
其他回答
我们可以创建ParentComponent并使用handleInputChange方法来更新ParentComponent的状态。导入ChildComponent并将两个道具从父组件传递给子组件,即handleInputChange函数和count。
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库进行道具类型检查。
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 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设置较低级别的状态。
这似乎对我有用
家长:
...
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>
我已经多次使用这个页面的顶级答案,但在学习React的时候,我发现了一个更好的方法,没有绑定,也没有道具内的内联函数。
看看这里:
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})
}
你可以在这里阅读更多。
我喜欢关于传递函数的答案。这是一个非常方便的技巧。
On the flip side you can also achieve this using pub/sub or using a variant, a dispatcher, as Flux does. The theory is super simple. Have component 5 dispatch a message which component 3 is listening for. Component 3 then updates its state which triggers the re-render. This requires stateful components, which, depending on your viewpoint, may or may not be an anti-pattern. I'm against them personally and would rather that something else is listening for dispatches and changes state from the very top-down (Redux does this, but it adds additional terminology).
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的调度程序捆绑非常简单。它只是简单地注册回调,并在任何分派发生时调用它们,传递分派上的内容(在上面的简洁示例中,分派没有有效负载,只有一个消息id)。如果对您更有意义的话,您可以很容易地将其调整为传统的pub/sub(例如,从事件中使用EventEmitter或其他版本)。