React:属性更改时如何使用setState和渲染组件

时间:2019-05-01 22:06:25

标签: reactjs render

该应用应按特定输入过滤单词。我想在渲染组件时使用setState()调用一个函数,并且从技术上讲它正在工作,但是控制台中有警告。

  

警告:无法在现有状态转换过程中(例如在render内进行更新)。渲染方法应该纯粹是props和state的函数。

我猜想这是因为我正在不应该在render函数中调用函数,但是我应该怎么做呢?

class UsersList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      allUsers: ["Michał", "Ania", "Kasia", "Tomek", "Hubert", "Jan", "Martyna", "Rafał", "Bartłomiej"],
      filteredUsers: [],
      input: null
    }
  }

  filter() {
    if (this.state.input !== this.props.inputValue) {
      const filtered = this.state.allUsers.filter(user => user.toLowerCase().includes(this.props.inputValue));
      this.setState({
        filteredUsers: filtered.map(user => <li key={user}>{user}</li>),
        input: this.props.inputValue
      })
    }

    return this.state.filteredUsers;
  }

  render() {
    this.filter()
    return (
      <ul>
        {this.state.filteredUsers}
      </ul>
    )
  }
}

class App extends React.Component {

  constructor() {
    super();

    this.state = {input: ""};
    this.handleInput = this.handleInput.bind(this);
  }

  handleInput(e) {
    this.setState({input: e.target.value})
  }

  render() {
    return (
      <div>
        <input onChange={this.handleInput} type="search"/>
        <UsersList inputValue={this.state.input} />
      </div>
    );
  }
}

2 个答案:

答案 0 :(得分:1)

这里的问题是由于在渲染过程中对组件的状态进行了更改所致。

您应该避免在组件render()函数期间直接设置组件状态(在组件filter()函数期间调用render()时会发生这种情况。)

相反,请考虑仅根据需要(例如,当state属性更改时)更新组件的inputValue。建议更改state值时更新prop的方法是通过getDerivedStateFromProps()组件生命周期挂钩。

这是一个示例,说明如何在组件中使用此挂钩:

class UsersList extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            allUsers: ["Michał", "Ania", "Kasia", "Tomek", 
                       "Hubert", "Jan", "Martyna", "Rafał",
                       "Bartłomiej"],
            filteredUsers: [],
            input: null
        }
    }

    /* Add this life cycle hook, it replaces filter(). Props are updated/incoming 
       props, state is current state of component instance */
    static getDerivedStateFromProps(props, state) {

        // The condition for prop changes that trigger an update
        if(state.input !== props.inputValue) {

            const filtered = state.allUsers.filter(user => user.toLowerCase().includes(props.inputValue));

            /* Return the new state object seeing props triggered an update */
            return {
                allUsers: state.allUsers
                filteredUsers: filtered.map(user => <li key={user}>{user}</li>),
                input: props.inputValue
            }
        }

        /* No update needed */
        return null;
    }

    render() {

        return (<ul>{this.state.filteredUsers}</ul>)
    }
}

希望这会有所帮助

答案 1 :(得分:0)

错误即将来临,因为它可能在组件内部创建一个无限循环。由于render方法在状态更新且您的函数this.filter正在执行状态更新时都会执行。现在,随着状态的更新,您的render方法再次触发该函数。

做到这一点的最佳方法是在lifecycle methods中或保持App中的用途,并通过始终传递已过滤用户列表以使其显示来使UserList成为愚蠢的组件。