ReactJS:警告:setState(…):不能在现有状态转换期间更新

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

<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;
304930 次浏览

看起来你不小心在渲染方法中调用了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>

如果你试图在recompose中向处理程序添加参数,请确保你在处理程序中正确地定义了参数。它本质上是一个咖喱函数,因此您希望确保需要正确数量的参数。本页提供了一个使用参数处理程序的好例子。

示例(摘自链接):

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)} />
)
}
}

这避免了在处理程序中编写匿名函数来修补没有在处理程序中提供足够参数名的问题。

我打电话的时候也出现了同样的错误

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

在构造函数中handleClick并不存在

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

解决方案=删除“this”绑定语句。

从react docs 向事件处理程序传递参数

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

我用来为组件打开弹窗的解决方案是React Bootstrap 4个组件

    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>
}
}
问题当然是这个绑定,而租用按钮与onClick处理程序。解决方案是在渲染时调用动作处理程序时使用箭头函数。是这样的: onClick={ () => this.handleButtonChange(false) } < / p >

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

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>
)
}

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

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>
)
}

render()调用中所做的任何状态更改都会发出相同的警告。

一个很难找到case的例子: 当基于状态数据呈现多选GUI组件时,如果状态没有任何显示,则调用resetOptions()被认为是该组件的状态更改

显而易见的修复方法是在componentDidUpdate()中执行resetOptions()而不是render()

通常你打电话的时候就会这样

onClick={this.handleButton()} -注意()而不是:

onClick={this.handleButton} -注意这里我们在初始化函数时没有调用它

这个问题在这里:onClick={this.handleButtonChange(false)}

当你将this.handleButtonChange(false)传递给onClick时,你实际上是在用value = false调用函数,并将onClick设置为函数的返回值,这是未定义的。同样,调用this.handleButtonChange(false)然后调用this.setState(),从而触发重新渲染,导致无限渲染循环。

解决方案是在lambda: onClick={() => this.handleButtonChange(false)}中传递函数。在这里,您将onClick设置为等于一个函数,该函数将在单击按钮时调用handleButtonChange(false)。

下面的例子可能会有所帮助:

function handleButtonChange(value){
console.log("State updated!")
}


console.log(handleButtonChange(false))
//output: State updated!
//output: undefined


console.log(() => handleButtonChange(false))
//output: ()=>{handleButtonChange(false);}

onClick函数必须传递一个返回handleButtonChange()方法的函数。否则它将自动运行,并以错误/警告结束。使用下面的方法来解决问题。

onClick={() => this.handleButtonChange(false)}