【问题标题】:Cannot update during an existing state transition - Not using any illegal setState()在现有状态转换期间无法更新 - 未使用任何非法 setState()
【发布时间】:2016-09-14 13:01:05
【问题描述】:

有人请帮我解决这个错误 在现有状态转换期间无法更新

当我渲染这个时,我收到如下错误

在现有状态转换期间无法更新(例如在 render 或其他组件的构造函数)。渲染方法应该是 props 和 state 的纯函数;构造函数的副作用是 反模式,但可以移动到componentWillMount

我尝试将 this.props.ifListChanged(this); 这段代码放在 componentWillUpdate 和 componentDidUpadate 中,但它花费了太多时间但没有错误(几乎 2分钟)。

import React from 'react';
import ListItemComponent from './ListItem.jsx';
import DropDownButtonComponent from './DropDownButton.jsx';
import DropDownStyle from '../../../../css/sass/drop-down.scss';

module.exports = React.createClass({
  handleClick: function () {
    this.setState({open: !this.state.open});
  },
  getInitialState: function () {
    return {
      open: false,
      //listItems: this.props.listItems,
      selectedItems:[],
      title: this.props.dropdownTitle
    }
  },
  handleItemClick: function (item) {
    var selectedItems = [];
    if(this.props.multiple == true){
      selectedItems = this.state.selectedItems;
      if(selectedItems.indexOf(item)==-1){
        selectedItems.push(item);
      }else{
        selectedItems.splice(selectedItems.indexOf(item),1)
      }
      this.setState({
        title: this.state.selectedItems.length+" selected",
        selectedItems: selectedItems
      });
    } else{
      selectedItems = [];
      selectedItems.push(item);
      this.setState({
        title: item,
        selectedItems: selectedItems,
        open: false
      });
    }
    //this.sendStateToParent();
  },
  sendStateToParent: function(){
    this.props.ifListChanged(this);
  },
  handleTextChange: function (event) {
    var filteredItems = [];
    this.props.listItems.map(function(item){
      if(item.toLowerCase().search(event.target.value.toLowerCase()) != -1){
        filteredItems.push(item);
      }
    },this);
    this.setState({
      listItems: filteredItems
    });
  },
  clearSelected: function(){
    this.setState({
      title: this.props.dropdownTitle,
      selectedItems: [],
    });
  },
  render: function () {
    this.props.ifListChanged(this);
    var index = 0;
    var list=[];
    if (this.state.listItems != undefined) {
      list = this.state.listItems.map(function (item) {
        return (
          <ListItemComponent
            key={index++}
            item={item}
            whenItemClicked={this.handleItemClick}
            className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
          />);
      }.bind(this));
    } else {
      list = this.props.listItems.map(function (item) {
        return (
          <ListItemComponent
            key={index++}
            item={item}
            whenItemClicked={this.handleItemClick}
            className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
          />);
      }.bind(this));
    }

    return <div className="btn-group bootstrap-select form-control">
      <DropDownButtonComponent
        whenClicked={this.handleClick}
        title={this.state.title}
      />
      <ul className={"dropdown-menu inner dropdown-menu " + (this.state.open ? "show" : "") }>
        {this.props.search? <li><input type="text" style={{margin:"auto", maxWidth:"96%"}} onChange={this.handleTextChange} placeholder="Search"/></li> :""}
        <li className="disabled"><a>Select from below list {this.props.multiple ? <i title="clear all" style={{fontSize:"15px"}} onClick={this.clearSelected} className="text-danger fa fa-ban pull-right"></i>: ""}</a></li>
        {list}
      </ul>
    </div>
  }
});

ListItem.jsx

import React from 'react';

module.exports = React.createClass({
  handleClick: function() {
    this.props.whenItemClicked(this.props.item);
  },
  render: function() {
    return <li onClick={this.handleClick} className={this.props.className}>
      <a>{this.props.item}</a>
    </li>
  }
});

DropDownButton.jsx

import React from 'react';

module.exports = React.createClass({
  render: function() {
    return <button  onClick={this.props.whenClicked} className="btn dropdown-toggle btn-default" type="button">
      <span className="filter-option pull-left">{this.props.title}</span>
      <span className="bs-caret"><i className="fa fa-chevron-down"></i></span>
    </button>
  }
});

提前感谢帮助我的人。谢谢。

【问题讨论】:

  • 我想你没有看到我的全部问题。请看一次代码。据我所知,我没有调用任何非法的 setState() 函数。 @TheReason
  • render() 中调用父级的某些函数是非常奇怪的(并且可能是非法的)。 this.props.ifListChanged(this) 是做什么的?
  • 我只想将 childComopnent 的状态发送给它的 parentComponent。但是当我在 handleItemClick() 中使用它时,之前的状态正在被发送。 @wintvelt
  • 家长如何处理您发送的过滤列表?我的猜测:该函数触发了父级的另一个渲染,因此也触发了子级的渲染,并且反应不允许这样做。这将是您设置中的道具/状态设计问题。

标签: javascript reactjs


【解决方案1】:

我认为您遇到了道具/状态设计问题。您的渲染函数中的this.props.ifListChanged(this) 非常可疑。您的渲染功能不需要向父母发出任何信号。 Parent 已经知道它发送的所有 props,如果 parent 需要知道 state,那么它很可能一开始就不应该是 state。

根据我从您的代码中收集到的信息,

  • 您的 List 组件接收未过滤的项目列表作为道具
  • 它有一个状态来跟踪过滤的项目和选定的项目。

如果两者的结果都需要发送到某处组件本身内部有另一个操作(例如,进程选择按钮或其他东西),这是一个很好的设置。
然后(并且只有那时)您会将状态发送给父母或其他地方。

如果父级需要一直了解这两者(例如,当流程按钮或流程操作在其他地方时),那么最好:

  • 在父级中定义一些 handleFilterUpdate 和 'handleSelectionUpdate` 方法,并将它们作为道具传递给子级。
  • 还将过滤后的列表和选择从父级传递给子级。
  • call the this.props.handleFilterUpdate and 'this.props.handleSelectionUpdate` from the child whenever something happens with selection or filters.

【讨论】:

  • 我已经尝试将它放在其他函数中并显式调用该函数。但是当我调用它时。它正在传递它的旧状态。假设我点击了ITEM1,它正在发送空数组[]。接下来我点击了ITEM2,它正在发送数组[ITEM1]。 @wintvelt
  • 好吧,我只能说你在这个问题上的设置不是一个理想的方向。使用回调函数,react 不应该向上发送前一个数组。但这是一个完全不同的问题。
  • 你能帮我解决这个问题吗@wintvelt
  • 当然,如果您在 SO 上发布一个新问题,以及您拨打电话的代码(显然使用错误的数组)。如果您在评论中在此处发布新问题的链接,那么我会从那里获取。
猜你喜欢
  • 2017-12-20
  • 1970-01-01
  • 2021-08-08
  • 2017-05-16
  • 2017-05-31
  • 2017-01-05
  • 2016-09-20
  • 2016-12-13
  • 2016-10-10
相关资源
最近更新 更多