J'essaie de refactoriser le code suivant à partir de ma vue de rendu:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>
à une version où la liaison est dans le constructeur. La raison en est que lier dans la vue de rendu me posera des problèmes de performances, en particulier sur les téléphones mobiles bas de gamme.
J'ai créé le code suivant, mais je reçois constamment les erreurs suivantes (beaucoup d'entre elles). On dirait que l'application se met en boucle:
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`.
Ci-dessous le code que j'utilise:
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;
On dirait que vous appelez accidentellement la méthode handleButtonChange
dans votre méthode de rendu, vous voudrez probablement faire onClick={() => this.handleButtonChange(false)}
à la place.
Si vous ne voulez pas créer un lambda dans le gestionnaire onClick, je pense que vous aurez besoin de deux méthodes liées, une pour chaque paramètre.
Dans la constructor
:
this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);
Et dans la méthode render
:
<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>
From react docs Passage d'arguments aux gestionnaires d'événements
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
Si vous essayez d'ajouter des arguments à un gestionnaire dans recompose
, assurez-vous de définir vos arguments correctement dans le gestionnaire. Il s’agit essentiellement d’une fonction curry, vous voulez donc vous assurer d’exiger le nombre correct d’arguments. Cette page a un bon exemple d'utilisation d'arguments avec des gestionnaires.
Exemple (à partir du lien):
withHandlers({
handleClick: props => (value1, value2) => event => {
console.log(event)
alert(value1 + ' was clicked!')
props.doSomething(value2)
},
})
pour votre enfant HOC et chez le parent
class MyComponent extends Component {
static propTypes = {
handleClick: PropTypes.func,
}
render () {
const {handleClick} = this.props
return (
<div onClick={handleClick(value1, value2)} />
)
}
}
cela évite d’écrire une fonction anonyme de votre gestionnaire pour corriger le problème en ne fournissant pas suffisamment de noms de paramètres sur votre gestionnaire.
Je donne un exemple générique pour une meilleure compréhension, dans le code suivant
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>
)
}
Lors de la fourniture d'accessoires, j'appelle la fonction directement, cette opération a une exécution en boucle infinie et vous renvoie l'erreur. Supprimez l'appel de fonction, tout fonctionne normalement
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>
)
}
J'ai eu la même erreur quand j'appelais
this.handleClick = this.handleClick.bind(this);
dans mon constructeur quand handleClick n'existait pas
(Je l'avais effacé et j'avais accidentellement laissé la déclaration contraignante "ceci" dans mon constructeur).
Solution = supprimer la déclaration de liaison "this".
La solution que j'utilise pour ouvrir Popover pour les composants est reactstrap (composants 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>
}
}
Ce même avertissement sera émis lors de tout changement d'état effectué lors d'un appel render()
.
Exemple de cas difficile à trouver: Lors du rendu d'un composant d'interface graphique à sélection multiple basé sur des données d'état, si state n'a rien à afficher, un appel à resetOptions()
est considéré comme un changement d'état pour ce composant.
La solution évidente est de faire resetOptions()
dans componentDidUpdate()
au lieu de render()
.