prevstate - ReactJS: Advertencia: setState(...): No se puede actualizar durante una transición de estado existente
setstate prevstate (8)
Estoy tratando de refactorizar el siguiente código desde mi vista de renderizado:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>
a una versión donde el enlace está dentro del constructor. La razón de esto es que el enlace en la vista de renderizado me dará problemas de rendimiento, especialmente en teléfonos móviles de gama baja.
He creado el siguiente código, pero constantemente recibo los siguientes errores (muchos de ellos). Parece que la aplicación entra en un bucle:
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`.
A continuación se muestra el código que uso:
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;
De reaccionar documentos Pasar argumentos a controladores de eventos
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
El problema es sin duda este enlace mientras se desgarra el botón con el controlador onClick.
La solución es utilizar la función de flecha al llamar al controlador de acciones mientras se procesa.
De esta manera:
onClick={ () => this.handleButtonChange(false) }
Esta misma advertencia se emitirá en cualquier cambio de estado realizado en una llamada
render()
.
Un ejemplo de un caso difícil de encontrar: cuando se procesa un componente de GUI de selección múltiple basado en datos de estado, si el estado no tiene nada que mostrar, una llamada a
resetOptions()
se considera un cambio de estado para ese componente.
La solución obvia es hacer
resetOptions()
en
componentDidUpdate()
lugar de
render()
.
Estoy dando un ejemplo genérico para una mejor comprensión, en el siguiente código
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>
)
}
Al proporcionar accesorios, llamo a la función directamente, este wold tiene una ejecución de bucle infinito y le daría ese error. Elimine la función de llamada, todo funciona normalmente.
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>
)
}
La solución que uso para abrir Popover para componentes es 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>
}
}
Parece que accidentalmente estás llamando al método
handleButtonChange
en tu método de representación, probablemente quieras hacer
onClick={() => this.handleButtonChange(false)}
lugar.
Si no desea crear una lambda en el controlador onClick, creo que necesitará tener dos métodos enlazados, uno para cada parámetro.
En el
constructor
:
this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);
Y en el método de
render
:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>
Recibí el mismo error cuando estaba llamando
this.handleClick = this.handleClick.bind(this);
en mi constructor cuando handleClick no existía
(Lo borré y accidentalmente dejé la declaración vinculante "this" en mi constructor).
Solución = eliminar la declaración vinculante "this".
Si está intentando agregar argumentos a un controlador en
recompose
, asegúrese de definir sus argumentos correctamente en el controlador.
Es esencialmente una función currificada, por lo que debe asegurarse de requerir el número correcto de argumentos.
Esta página tiene un buen ejemplo de uso de argumentos con manejadores.
Ejemplo (del enlace):
withHandlers({
handleClick: props => (value1, value2) => event => {
console.log(event)
alert(value1 + '' was clicked!'')
props.doSomething(value2)
},
})
para su hijo HOC y en el padre
class MyComponent extends Component {
static propTypes = {
handleClick: PropTypes.func,
}
render () {
const {handleClick} = this.props
return (
<div onClick={handleClick(value1, value2)} />
)
}
}
Esto evita escribir una función anónima fuera de su controlador para corregir el problema al no proporcionar suficientes nombres de parámetros en su controlador.