我的结构如下:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
组件3应根据组件5的状态显示一些数据。 由于道具是不可变的,我不能简单地将它保存在组件1中并转发它,对吗?是的,我已经阅读过有关redux的内容,但并不想使用它。我希望只要有反应就可以解决它。我错了吗?
答案 0 :(得分:468)
对于子父母沟通,你应该传递一个功能,将状态从父母设置为孩子,就像这样
class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
}
handler(someValue) {
this.setState({
someVar: someValue
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}
这样,孩子可以通过调用带有props的函数来更新父级的状态。
但您必须重新考虑组件的结构,因为据我所知,组件5和组件3不相关。
一种可能的解决方案是将它们包含在更高级别的组件中,该组件将包含组件1和3的状态。该组件将通过props设置较低级别的状态。
答案 1 :(得分:36)
我找到了以下工作解决方案,将onClick函数参数从child传递给父组件:
传递方法的版本()
//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")
);
}
答案 2 :(得分:11)
这就是我们如何使用新的 useState
钩子来实现的。
方法 - 将 state changer 函数作为 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>
)
}
答案 3 :(得分:6)
我喜欢传递函数的答案,这是一种非常方便的技术。
另一方面,您也可以使用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)。如果这对你更有意义,你可以很容易地将它改编为传统的pub / sub(例如,使用来自事件的EventEmitter或其他版本)。
答案 4 :(得分:6)
我要感谢最赞同的回答,它给了我自己的问题的想法,基本上是通过箭头功能和从子组件传递参数来实现的:
php artisan migrate:fresh
php artisan migrate
希望它可以帮助某人。
答案 5 :(得分:4)
我找到了以下工作解决方案,使用param:
将onClick函数参数从child传递给父组件父类:
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>
)
} }
答案 6 :(得分:2)
如果您需要在任何级别的孩子与父母之间进行沟通,那么最好使用上下文。在父组件中定义子项可以调用的上下文,例如
在案例组件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>
)}
您可以在repo
找到演示项目答案 7 :(得分:2)
我们可以通过将一个函数作为 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 是从父母传递过来的道具。这可以从子进程中的事件 listeners 调用,因此状态将在那里更新。
答案 8 :(得分:2)
上面给出的大多数答案都是针对基于React.Component的设计的。如果您在最近的React库升级中使用useState
,请遵循此answer
答案 9 :(得分:2)
如果这种情况并没有遍及每个地方,那么您可以使用React的上下文,特别是如果您不想引入状态管理库引入的所有开销时。另外,它更容易学习。但是要小心,您可能会过度使用它并开始编写错误的代码。基本上,您定义了一个Container组件(将为您保留并保持该状态),从而使所有对写入/读取该数据段感兴趣的组件成为其子级(不一定是直接子级)
https://reactjs.org/docs/context.html
您也可以正确使用普通的React。
<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />
将doSomethingAbout5传递到组件1
<Component1>
<Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
<Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>
如果这是一个常见问题,您应该开始考虑将应用程序的整个状态转移到其他地方。您有几种选择,最常见的是:
https://facebook.github.io/flux/
基本上,当某些情况使状态更新时,您发送命令而不是在组件中管理应用程序状态。组件也从此容器中获取状态,因此所有数据都被集中。这并不意味着不能再使用本地状态,而是一个更高级的主题。
答案 10 :(得分:1)
这是获取两种方式绑定数据的简短片段。
计数器显示来自父级的值并从子级更新
class Parent extends 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 <Child handler={this.handler} count={this.state.count} />
}
}
class Child extends React.Component {
render() {
return <button onClick={this.props.handler}>Count {this.props.count}</button>
}
}
ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 11 :(得分:1)
根据您的问题,我了解到您需要在基于组件 5 状态的组件 3 中显示一些条件数据。方法:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Class Component3 extends React.Component {
state = {
someData = true
}
checkForData = (result) => {
this.setState({someData : result})
}
render() {
if(this.state.someData) {
return(
<Component5 hasData = {this.checkForData} />
//Other Data
);
}
else {
return(
//Other Data
);
}
}
}
export default Component3;
class Component5 extends React.Component {
state = {
dataValue = "XYZ"
}
checkForData = () => {
if(this.state.dataValue === "XYZ") {
this.props.hasData(true);
}
else {
this.props.hasData(false);
}
}
render() {
return(
<div onLoad = {this.checkForData}>
//Conditional Data
</div>
);
}
}
export default Component5;
答案 12 :(得分:1)
因此,如果要更新父组件,
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
}
并传递给子组件
因此Child组件可以访问props对象中的name值,例如props.onChange
它是通过使用渲染道具来完成的。
现在,Child组件具有设置为onclick事件的按钮“ Click”,以调用在其props参数对象中通过onChnge传递给它的处理程序方法。所以现在Child中的this.props.onChange将输出方法保存在Parent类中 参考和鸣谢: Bits and Pieces
答案 13 :(得分:1)
我已经多次使用此页面中评分最高的答案,但是在学习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。希望这对某人有用=)
答案 14 :(得分:1)
似乎我们只能将数据从父级传递到子级,因为react促进了单向数据流,但是为了使父级在其“子级组件”中发生某些事情时进行自身更新,我们通常使用所谓的“回调函数”。
我们将父级中定义的函数作为“ props”传递给子级, 从子级调用该函数在父级中触发它 组件。
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>
在此示例中,我们可以通过将函数传递给其直接子级来使数据从SubChild-> Child-> Parent传递。
答案 15 :(得分:1)
-我们可以创建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。该组件是无状态的,因为子组件没有状态。我们使用道具类型库进行道具类型检查。
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;
答案 16 :(得分:0)
我这样做的方式。
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>
}
}
答案 17 :(得分:-3)
<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.