不能在React

时间:2017-04-18 20:18:20

标签: reactjs webpack babeljs

我有以下组件,每次尝试使用setState函数时都会收到警告:

Warning: setState(...): Can only update a mounted or mounting component. 
This usually means you called setState() on an unmounted component. 
This is a no-op. Please check the code for the LoginView component

我尝试添加componentDidMountcomponentWillUnmount仅用于调试此问题,而在this.setState回调中,状态已更新,我将mounted视为真,当我尝试输入我的输入onInputChange this.state.mounted仍然是假的,并且不会更新状态......

我无法弄清楚我做错了什么,因为我试图在网上关注示例。

import React from 'react';
import { bindActionCreators } from 'redux'
import BaseComponent from 'BaseComponent';
import * as loginActions from './LoginActions';
import { connect } from 'react-redux'

const LOGIN_ACTIONS = loginActions.LOGIN_ACTIONS

class LoginView  extends React.Component {

  constructor(props){
    super(props);

    this.props = props;
    this.setupState.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
    this.state = this.setupState();
    this.submitForm = this.submitForm.bind(this);
    this.render = this.render.bind(this);

  }

  setupState (){
    debugger;
    return {
      mounted: false,
      fields : {
        email: '',
        password:'',
      },
    };
  }
  componentDidMount() {
    debugger;
    this.setState({ mounted: true }, function() {
      debugger;
      console.log(this);
    }.bind(this));

  }

  componentWillUnmount() {
    debugger;
    this.setState({ mounted: false })

  }

  onInputChange(evt){
    const fields = this.state.fields;
    fields[evt.target.name] = evt.target.value;
    if(this.state.mounted){
      this.setState({fields : fields});
    }
     // this.state.fields = fields;
  }

  submitForm(evt){
    evt.preventDefault();
    //debugger;
    //this.actions.login(this.state.fields.email, this.state.fields.password);
  }


  render() {

        return (
            <div>

                    <h1>Swirl Simulator Manager</h1>
                    <form onSubmit={this.submitForm}>
                        <label>Username</label>
            <input type='text' placeholder='Email'
              name='email'
              value={this.state.fields.email}
              onChange={this.onInputChange} />
            <br />
                        <label>Password</label><input type='password'name='password' value={this.state.fields.password} onChange={this.onInputChange}/>
            <br />
            <input type="submit" />
                    </form>
            </div>
        )
    }
}
export default connect(
  state => { return { auth: state.auth }; },
  dispatch => { return { actions: bindActionCreators(loginActions, dispatch) }; }
)(LoginView);

UPDATE:

我能够通过在render函数中绑定它来使它工作,如下所示:

 <input type='text' placeholder='Email'
              name='email'
              value={this.state.fields.email}
              onChange={this.onInputChange.bind(this)} />

但我不明白为什么会这样,而this.onInputChange.bind(this)在构造函数中并不是

我也尝试过使用箭头功能:

onInputChange = (evt) => {
    const fields = this.state.fields;
    fields[evt.target.name] = evt.target.value;
      this.setState({fields : fields}, ()=> {
        console.log(this.state);
      });
  }

这导致了与在构造函数

中完成的问题相同的问题

更新2 - 更新代码以排除componentWillMount

import React from 'react';
import { bindActionCreators } from 'redux'

export default class LoginView  extends React.Component {
  state = {
    fields : {
      email: '',
      password:'',
    },
  };
  constructor(props){
    debugger;
    super(props);

    //this.props = props;
    //this.setupState.bind(this);
    //this.render = this.render.bind(this);

    // This doesn't allow me to set state in onInputChange
    this.onInputChange = this.onInputChange.bind(this);
    this.submitForm = this.submitForm.bind(this);


  }

  onInputChange(evt) {
    evt.preventDefault();
    const fields = this.state.fields;
    fields[evt.target.name] = evt.target.value;
    this.setState({fields : fields}, ()=> {
      console.log(this.state);
    });
  }

  /*  This also does not allow me to setState
  onInputChange = (evt) => {
    evt.preventDefault();
    const fields = this.state.fields;
    fields[evt.target.name] = evt.target.value;
    this.setState({fields : fields}, ()=> {
      console.log(this.state);
    });
  }
  */

  submitForm(evt){
    evt.preventDefault();
    console.log(this.state);
  }


  render() {

        return (
        <div>

            <h1>Login</h1>
            <form onSubmit={this.submitForm}>
                <label>Username</label>
                <input type='text' placeholder='Email'
                       name='email'
                       value={this.state.fields.email}
                       onChange={this.onInputChange} />
                <br />
                <label>Password</label>
                <input type='password'
                       name='password' 
                       value={this.state.fields.password} 
                       onChange={this.onInputChange.bind(this)}/>
                <br />
                <input type="submit" />
            </form>
        </div>
        )
    }
}

如果我更改密码字段的输入,一切都按预期工作,但如果我使用构造函数来绑定它或者如果我使用箭头函数(两者都在上面注释掉),则从不在电子邮件上

以防这是由webpack引起的,这是我的webpack配置:

const webpack = require('webpack');
const path = require('path');

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('[name].bundle.css')

const config = {
  context: path.resolve(__dirname, 'src'),
  devtool: 'inline-source-map',
  entry: {
    'app' : [
      'react-hot-loader/patch',
      './App.js'
    ]
  },
  output: {
    path: path.resolve(__dirname, 'build'),
    publicPath: '/build',
    filename: '[name].bundle.js'
  },
  module: {
    rules: [{
      test: /\.jsx?$/,
      include: path.resolve(__dirname, 'src'),
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            //'es2017',
            'es2016',
            "stage-0",
            "react"
          ],
          plugins:[
            'react-hot-loader/babel'
          ]
        }
      }]
    },
    {
      test: /\.scss$/,
      include: /node_modules/,
      loader: extractCSS.extract(['css-loader','sass-loader'])
    }]
  }, // End : module
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    extractCSS,
  ],
  resolve: {
    alias: {
      components : path.resolve(__dirname, 'src/components'),
      BaseComponent$ : path.resolve(__dirname, 'src/components/BaseComponent.js'),
      'views' : path.resolve(__dirname, 'src/views'),
      'modules' : path.resolve(__dirname, 'src/modules'),
      'services' : path.resolve(__dirname, 'src/services')
    }
  }
}

module.exports = config

和我的依赖

"devDependencies": {
    "babel-core": "6.24.0",
    "babel-loader": "6.4.1",
    "babel-preset-es2016": "6.22.0",
    "babel-preset-es2017": "6.22.0",
    "babel-preset-react": "6.23.0",
    "babel-preset-stage-0": "6.22.0",
    "css-loader": "0.27.3",
    "extract-text-webpack-plugin": "2.1.0",
    "node-sass": "4.5.1",
    "redux-devtools-extension": "2.13.0",
    "sass-loader": "6.0.3",
    "webpack": "2.3.2",
    "webpack-dev-server": "2.4.2"
  },
  "dependencies": {
    "css-loader": "0.27.3",
    "node-sass": "4.5.1",
    "react": "15.4.2",
    "react-dom": "15.4.2",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-redux": "5.0.3",
    "react-router-dom": "4.0.0",
    "redux": "3.6.0",
    "redux-thunk": "2.2.0",
    "sass-loader": "6.0.3",
    "style-loader": "0.16.0"
  }

2 个答案:

答案 0 :(得分:1)

不确定,但这些更改不是必需的,可能会解决您的问题:

1。删除以下行:

this.props = props;
this.setupState.bind(this);
this.render = this.render.bind(this);  //binding of render method is not required

2。setState方法移除componentWillUnmount,因为在setState之后,React将尝试执行re-rendering

componentWillUnmount() {
    debugger;
   // this.setState({ mounted: false })
}

根据DOC

  

componentWillUnmount()在组件出现之前立即被调用   未安装和销毁。在此方法中执行任何必要的清理,   例如使计时器无效,取消网络请求。

答案 1 :(得分:0)

不确定您为什么要跟踪组件中的已装入或未装入状态。问题的根源基本上是这样的:

componentWillUnmount() {
    this.setState({ mounted: false })
  }

尝试设置一个组件的状态是没有意义的,这个组件的状态将不可避免地被反应卸载,所以你得到一个警告,你正在做的事情基本上是no-op(没有操作)并且没有影响。我强烈建议你阅读component lifecycle并澄清你的意思