レンダービューから次のコードをリファクタリングしようとしています。
<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;
Renderメソッドで誤ってhandleButtonChange
メソッドを呼び出しているように見えますが、代わりにonClick={() => this.handleButtonChange(false)}
を実行することをお勧めします。
OnClickハンドラでラムダを作成したくない場合は、各パラメータに1つずつ、合計2つのメソッドを用意する必要があります。
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>
理解を深めるために、一般的な例を挙げています。
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>
)
}
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)} />
)
}
}
これはあなたのハンドラから十分なパラメータ名を供給しないという問題を修正するためにあなたのハンドラから無名関数を書くことを避けます。
反応ドキュメントから イベントハンドラに引数を渡す
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
これと同じ警告が、render()
呼び出しで行われたすべての状態変更に対して発行されます。
ケースを見つけるのが難しい例:状態データに基づいて複数選択GUIコンポーネントをレンダリングするときに、stateに何も表示されない場合、resetOptions()
の呼び出しはそのコンポーネントの状態変更と見なされます。
明らかな修正はresetOptions()
の代わりにcomponentDidUpdate()
でrender()
を行うことです。
電話をかけていたときに同じエラーが発生しました
this.handleClick = this.handleClick.bind(this);
handleClickが存在しなかったときの私のコンストラクタの中で
(私はそれを消してしまい、誤って "this"というバインディングステートメントをコンストラクタに残していました)。
解決策= "this"バインディングステートメントを削除してください。
Popover for componentsを開くために私が使用する解決策は 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>
}
}
OnClickハンドラでボタンを貸している間の問題は確かにthisバインディングです。解決策は、レンダリング中にアクションハンドラを呼び出すときに矢印関数を使用することです。このように:onClick={ () => this.handleButtonChange(false) }