为什么当子级调用父函数时父组件中的状态不会改变?

时间:2019-04-23 17:19:07

标签: reactjs redux

我正在使用引导程序模态,并在元素上的单击事件上打开它,但是当我单击模态右上角的“ x”时无法关闭它。 问题是我确实通过道具成功地将状态从父项传递给子项,但是当我在子项内调用函数“ lgClose”时,它转到父项组件,但实际上并未将状态位置更改为“ false”。 我可以看到它进入函数内部,因为我输入了“ console.log('im in function')”,并且可以看到它。为什么在父组件中状态未更改为false?

import React, { Component } from 'react';
import { Link } from 'react-router-dom'
import { connect } from 'react-redux';
import { getAllUsers,getMessages } from './../actions';
import { bindActionCreators} from 'redux';
import { Button, Modal } from 'react-bootstrap';
import  ContainerModal  from './../components/popup_modal';

// parent component
class MainContainer extends Component {

  constructor(props, context) {
    super(props, context);

    this.state = {
      lgShow: false
    };
  }

  componentWillMount(){
    this.props.getAllUsers();
  }


  renderList = ({list}) => {
    if(list){
      return list.map((item)=>{
        return(
          <div key={item._id} className="item-list" onClick={() => this.setState({lgShow: true})}>
                            
              
              <div className="title">{item.firstName} {item.lastName}</div>
              <div className="body">{item.age}</div>

              <div>
                    
                <ContainerModal lgShow={this.state.lgShow} lgClose={this.lgClose}/>                                    

              </div>
              
          </div>
        )
      })
    }
  }

  lgClose = () => {
    this.setState({lgShow:false});
    console.log('im in the function');
  } 


  render() {
    console.log(this.state);

    return (
        <div className="App">
          <div className="top">
            <h3>Messages</h3>
            <Link to="/form">Add</Link>
          </div>
          <div className="messages_container">
            {this.renderList(this.props.users)}
          </div>           
              
        </div>
    );
  }
}

function mapStateToProps(state) {
  return {
      messages:state.messages,
      users:state.users
  }
}

function mapDispatchToProps (dispatch) { 
  return bindActionCreators({getAllUsers,getMessages},dispatch);
}


export default connect(mapStateToProps,mapDispatchToProps)(MainContainer);



import React from 'react';
import { Button, Modal } from 'react-bootstrap';

// child component
const ContainerModal = (props) => {
    
    return (
        <div>
            <Modal                  
                  size="lg"
                  show={props.lgShow}
                  onHide={ props.lgClose }
                  aria-labelledby="example-modal-sizes-title-lg"
            >

                  <Modal.Header closeButton>
                    <Modal.Title id="example-modal-sizes-title-lg">
                      Large Modal
                    </Modal.Title>
                  </Modal.Header>

                  <Modal.Body>item</Modal.Body>

            </Modal>

        </div>        
       
    )
}

export default ContainerModal;

3 个答案:

答案 0 :(得分:0)

似乎this函数中的lgClose没有指向MainContainer。 如果是这种情况,一种解决方法是将lgClose函数绑定到构造函数中的MainContainer:

constructor(props, context) {
    super(props, context);

    this.state = {
      lgShow: false
    };

    this.lgClose = this.lgClose.bind(this); // Add this line
}

希望这会有所帮助:)

答案 1 :(得分:0)

在您的ContainerModal中尝试以下操作:

import React from 'react';
import { Button, Modal } from 'react-bootstrap';

// child component
const ContainerModal = (props) => {

    return (
        <div>
            <Modal                  
                  {...props}
                  size="lg"
                  aria-labelledby="example-modal-sizes-title-lg"
            >

                  <Modal.Header closeButton>
                    <Modal.Title id="example-modal-sizes-title-lg">
                      Large Modal
                    </Modal.Title>
                  </Modal.Header>

                  <Modal.Body>item</Modal.Body>

            </Modal>

        </div>        

    )
}

export default ContainerModal;

在renderList中,执行以下操作:

 <ContainerModal show={this.state.lgShow} onHide={this.lgClose} />

答案 2 :(得分:0)

这是您的 lgShow 保持真实的原因。

此说明将稍长一些。所以,请忍受我。

这是您所做的。

您已将 ContainerModal 作为 div (className =“ item-list”)的子级添加到具有onClick的 renderList 方法中侦听器附加到自身。 当您单击列表项时,它可以正常工作并出现模态,但是当您单击模态上的关闭按钮时,事情就会变得混乱。

这是因为 div (className =“ item-list”)的onClick侦听器在 再次调用ContainerModal的点击监听器,将 lgShow 设置为 true 。这种行为称为事件冒泡,其中父级和子级都以自下而上的方式接收事件(即,子级接收第一个事件,随后是父级)。 要验证此行为,请在div的onClick侦听器中添加console.log。

  

这里是github问题的link,用于说明事件冒泡

解决方案

首要的建议是将ContainerModal从renderList方法取出到根div。这是因为现在正在为您的每个列表项创建一个ContainerModal,这是不必要的。例如,如果列表中有10个用户,则要创建10个ContainerModal(要验证这一点,可以增加用户数量,并且可以看到模式的阴影变得更暗。)

上述问题的解决方案是将ContainerModal置于其onClick的根级别,该根级别与renderList中 div (className =“ item-list”)的onClick不一致。您的问题将得到解决。

这是修改后的解决方案。

import React, { Component } from 'react';
import { Link } from 'react-router-dom'
import { connect } from 'react-redux';
import { getAllUsers,getMessages } from './../actions';
import { bindActionCreators} from 'redux';
import { Button, Modal } from 'react-bootstrap';
import  ContainerModal  from './../components/popup_modal';

// parent component
class MainContainer extends Component {

  constructor(props, context) {
    super(props, context);

    this.state = {
      lgShow: false
    };
  }

  componentWillMount(){
    this.props.getAllUsers();
  }


  renderList = ({list}) => {
    if(list){
      return list.map((item)=>{
        return(
          <div key={item._id} className="item-list" onClick={() => this.setState({lgShow: true})}>
                            
              
              <div className="title">{item.firstName} {item.lastName}</div>
              <div className="body">{item.age}</div>

              <div>
                    
                {/* <ContainerModal lgShow={this.state.lgShow} lgClose={this.lgClose}/> */}                                

              </div>
              
          </div>
        )
      })
    }
  }

  lgClose = () => {
    this.setState({lgShow:false});
    console.log('im in the function');
  } 


  render() {
    console.log(this.state);

    return (
        <div className="App">
          <div className="top">
            <h3>Messages</h3>
            <Link to="/form">Add</Link>
          </div>
          <div className="messages_container">
            {this.renderList(this.props.users)}
          </div>           
          <ContainerModal lgShow={this.state.lgShow} lgClose={this.lgClose}/>
        </div>
    );
  }
}

function mapStateToProps(state) {
  return {
      messages:state.messages,
      users:state.users
  }
}

function mapDispatchToProps (dispatch) { 
  return bindActionCreators({getAllUsers,getMessages},dispatch);
}


export default connect(mapStateToProps,mapDispatchToProps)(MainContainer);



import React from 'react';
import { Button, Modal } from 'react-bootstrap';

// child component
const ContainerModal = (props) => {
    
    return (
        <div>
            <Modal                  
                  size="lg"
                  show={props.lgShow}
                  onHide={ props.lgClose }
                  aria-labelledby="example-modal-sizes-title-lg"
            >

                  <Modal.Header closeButton>
                    <Modal.Title id="example-modal-sizes-title-lg">
                      Large Modal
                    </Modal.Title>
                  </Modal.Header>

                  <Modal.Body>item</Modal.Body>

            </Modal>

        </div>        
       
    )
}

export default ContainerModal;

请注意容器模式的更改位置。其余代码都可以。

我还向代码沙箱上传了一个有效的解决方案。看看吧。

Edit xlxp61vy5q

希望这会有所帮助。