首页 文章

ReactJS:警告:setState(...):在现有状态转换期间无法更新

提问于
浏览
135

我试图从我的渲染视图重构以下代码:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>

到绑定在构造函数中的版本 . 原因是渲染视图中的绑定会给我带来性能问题,特别是在低端手机上 .

我创建了以下代码,但我不断收到以下错误(很多错误) . 看起来应用程序进入循环:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

以下是我使用的代码:

var React = require('react');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var Button = require('react-bootstrap/lib/Button');
var Form = require('react-bootstrap/lib/Form');
var FormGroup = require('react-bootstrap/lib/FormGroup');
var Well = require('react-bootstrap/lib/Well');

export default class Search extends React.Component {

    constructor() {
        super();

        this.state = {
            singleJourney: false
        };

        this.handleButtonChange = this.handleButtonChange.bind(this);
    }

    handleButtonChange(value) {
        this.setState({
            singleJourney: value
        });
    }

    render() {

        return (
            <Form>

                <Well style={wellStyle}>

                    <FormGroup className="text-center">

                        <ButtonGroup>
                            <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button>
                            <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button>
                        </ButtonGroup>
                    </FormGroup>

                </Well>

            </Form>
        );
    }
}

module.exports = Search;

8 回答

  • 1

    render() 调用中完成的任何状态更改都将发出相同的警告 .

    棘手查找案例的示例:当基于状态数据呈现多选GUI组件时,如果状态没有显示任何内容,则对 resetOptions() 的调用被视为该组件的状态更改 .

    显而易见的解决方法是在 componentDidUpdate() 中执行 resetOptions() 而不是 render() .

  • 0

    看起来你不小心在你的渲染方法中调用 handleButtonChange 方法,你可能想要改为 onClick={() => this.handleButtonChange(false)} .

    如果您不想在onClick处理程序中创建lambda,我认为您需要有两个绑定方法,每个参数一个 .

    constructor

    this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
    this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);
    

    render 方法中:

    <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
    <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>
    
  • 0

    来自反应文档Passing arguments to event handlers

    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
    
  • 0

    如果您尝试在 recompose 中向处理程序添加参数,请确保在处理程序中正确定义参数 . 它本质上是一个curried函数,因此您需要确保需要正确数量的参数 . This page has a good example of using arguments with handlers.

    示例(来自链接):

    withHandlers({
      handleClick: props => (value1, value2) => event => {
        console.log(event)
        alert(value1 + ' was clicked!')
        props.doSomething(value2)
      },
    })
    

    为您的孩子HOC和父母

    class MyComponent extends Component {
      static propTypes = {
        handleClick: PropTypes.func, 
      }
      render () {
        const {handleClick} = this.props
        return (
          <div onClick={handleClick(value1, value2)} />
        )
      }
    }
    

    这样可以避免从处理程序中编写匿名函数来修复问题而不在处理程序上提供足够的参数名称 .

  • 237

    我打电话时遇到同样的错误

    this.handleClick = this.handleClick.bind(this);
    

    handleClick didn't exist 在我的构造函数中

    (我删除了它,并在我的构造函数中不小心留下了“this”绑定语句) .

    Solution =删除“this”绑定语句 .

  • 1

    我给出了一个更好理解的通用示例,在下面的代码中

    render(){
        return(
          <div>
    
            <h3>Simple Counter</h3>
            <Counter
              value={this.props.counter}
              onIncrement={this.props.increment()} <------ calling the function
              onDecrement={this.props.decrement()} <-----------
              onIncrementAsync={this.props.incrementAsync()} />
          </div>
        )
      }
    

    当提供道具我直接调用函数时,这个wold有一个无限循环执行并且会给你那个错误,删除函数调用一切正常 .

    render(){
        return(
          <div>
    
            <h3>Simple Counter</h3>
            <Counter
              value={this.props.counter}
              onIncrement={this.props.increment} <------ function call removed
              onDecrement={this.props.decrement} <-----------
              onIncrementAsync={this.props.incrementAsync} />
          </div>
        )
      }
    
  • 1

    我用来为组件打开Popover的解决方案是reactstrap (React Bootstrap 4 components) .

    class Settings extends Component {
            constructor(props) {
                super(props);
    
                this.state = {
                  popoversOpen: [] // array open popovers
                }
            }
    
            // toggle my popovers
            togglePopoverHelp = (selected) => (e) => {
                const index = this.state.popoversOpen.indexOf(selected);
                if (index < 0) {
                  this.state.popoversOpen.push(selected);
                } else {
                  this.state.popoversOpen.splice(index, 1);
                }
                this.setState({ popoversOpen: [...this.state.popoversOpen] });
            }
    
            render() {
                <div id="settings">
                    <button id="PopoverTimer" onClick={this.togglePopoverHelp(1)} className="btn btn-outline-danger" type="button">?</button>
                    <Popover placement="left" isOpen={this.state.popoversOpen.includes(1)} target="PopoverTimer" toggle={this.togglePopoverHelp(1)}>
                      <PopoverHeader>Header popover</PopoverHeader>
                      <PopoverBody>Description popover</PopoverBody>
                    </Popover>
    
                    <button id="popoverRefresh" onClick={this.togglePopoverHelp(2)} className="btn btn-outline-danger" type="button">?</button>
                    <Popover placement="left" isOpen={this.state.popoversOpen.includes(2)} target="popoverRefresh" toggle={this.togglePopoverHelp(2)}>
                      <PopoverHeader>Header popover 2</PopoverHeader>
                      <PopoverBody>Description popover2</PopoverBody>
                    </Popover>
                </div>
            }
        }
    
  • 2

    当使用onClick处理程序重新发送按钮时,问题肯定是这个绑定 . 解决方案是在渲染时调用动作处理程序时使用箭头函数 . 像这样: onClick={ () => this.handleButtonChange(false) }

相关问题