1. 程式人生 > >React 部落格系列 (2) React中的state和props更新

React 部落格系列 (2) React中的state和props更新

React中的state和props更新

github個人部落格原始碼持續更新中。。。

在搭建個人部落格的過程中,需要新增一個登陸窗體,登陸按鈕和登陸表單分別在不同的元件,登陸btn在元件HeaderCustom,登陸窗體和表單在FormLogin,由登陸btn控制FormLogin的顯示和隱藏,利用Redux進行狀態管理。


HeaderCustom

  onLogin = () => {
    this.setState({
      visible: true
    },()=>{
      console.log("onLogin_state"
); console.log(this.state); }); } render(){ return(.... <Menu.Item key="7" className="" style={ { lineHeight: '64px', position: "absolute", right: '0px', top: "0px" } }> <span onClick={ this.onLogin }> <Icon type="user" style={ { fontSize: 16, color
: '#1DA57A' } }/>{ this.props.username } </span> <UserLoginFrom visible={ loginFormVisible }></UserLoginFrom> </Menu.Item> ...); } const mapStateToProps = (state) => { var adminAccess = state.reducer_login.adminAccess; var loginVisible = state.reducer_login.loginFormVisible; return
{ adminAccess: adminAccess, loginFormVisible: loginVisible } }

FormLogin

  handleOk = () => {
        this._loginCheck()
        this.setState({
            loading: true
        });
        setTimeout(() => {
            this.setState({
                visible: false
            });
        }, 3000);
        this.props.changeLoginVisible({
            loginFormVisible:false
        })
    }

    handleCancel() {
        this.setState({
            visible: false
        });
        this.props.changeLoginVisible({
            loginFormVisible:false
        })
    }

    render() {
        const {getFieldDecorator} = this.props.form;
        const {visible, loading} = this.state;
        return (
            <Modal style={ { textAlign: "center" } } destroyOnClose={true} cancelText="取消" okText="登陸" visible={ visible } title="管理端登陸驗證" onOk={ this.handleOk.bind(this) } onCancel={ this.handleCancel.bind(this) }>
              <Form onSubmit={ this.handleSubmit } className="login-form">
               ......
              </Form>
            </Modal>
            );
    }

const mapDispatchToProps = (dispatch) => {
    return {
      changeAccess: (assessToAdmin) => {
        dispatch(changeAdminAccess(assessToAdmin))
      },
      changeLoginVisible:(loginFormVisible)=>{
        dispatch(closeUserLoginForm(loginFormVisible))          
      }
    }
  }

解決方法1

在實施的過程中,遇到了setState方法和props更新的困擾,由於每次關閉窗體後,傳遞給HeaderCoustom的props為 loginFormVisible:false,出現了再次點選登陸按鈕時窗體不顯示的情況,經過分析才發現,props物件沒有發生改變,render方法當然不會自動執行,故解決的辦法是在props物件中加入時間戳:

const mapStateToProps = (state) => {
  var adminAccess = state.reducer_login.adminAccess;
  var loginVisible = state.reducer_login.loginFormVisible;
  //加入 key:(new Date()).getTime() 時間戳 每次傳入的Props物件都不一樣 元件都會重新渲染一次
  return {
    adminAccess: adminAccess,
    loginFormVisible: loginVisible,
    key:(new Date()).getTime()
  }
}

在實施的過程中,還發現了setState執行後,state物件不會立馬改變,而是先執行render渲染後,才發生變化的。

  onLogin = () => {
    this.setState({
      visible: true
    },()=>{
      console.log("onLogin_state");
      console.log(this.state);//回撥函式函式在render執行後再觸發,此處列印的是變化後的state
    });
    console.log(this.state);//列印state變化前的物件
  }

解決方法2

放發一用到了redux重新整理父級組價的props,這在深層次的巢狀中是最有效的傳遞狀態的方法,但是在直接巢狀的父子元件中,感覺有些大材小用,父級元件可以直接繫結方法傳遞給子元件。

父級元件

  onLoginClose = () => {
    this.setState({
      visible: false
    }, () => {
      console.log("onLogin_close");
      console.log(this.state);
    });
  }

render(){
...
          <Menu.Item key="7" className="" style={ { lineHeight: '64px', position: "absolute", right: '0px', top: "0px" } }>
            <span onClick={ this.onLogin }> <Icon type="user" style={ { fontSize: 16, color: '#1DA57A' } }/>{ this.props.username } </span>
            <UserLoginFrom visible={ loginFormVisible } onClose={ this.onLoginClose.bind(this) }></UserLoginFrom>
          </Menu.Item>
}
...

子元件

    handleCancel() {
        this.setState({
            visible: false
        });
        console.log(this.props.onClose)
        this.props.onClose();
    }

將onClose傳遞給子元件 ,子元件狀態改變時,反饋給父級元件改變父級自身的狀態。