web-dev-qa-db-ja.com

componentDidUpdate()内のsetState()

ドロップダウンの高さと画面上の入力の位置に応じて、ドロップダウンを入力の下または上に移動するスクリプトを書いています。また、その方向に従って修飾子をドロップダウンに設定したいです。しかし、setState内でcomponentDidUpdateを使用すると、無限ループが作成されます(これは明らかです)

getDOMNodeを使用し、classnameを直接dropdownに設定することで解決策を見つけましたが、Reactツールを使用するより良い解決策があるはずです。誰も私を助けることができますか?

getDOMNodeを使用した作業コードの一部を次に示します(コードを簡素化するために配置ロジックを少し無視しました)

let SearchDropdown = React.createClass({
    componentDidUpdate(params) {
        let el = this.getDOMNode();
        el.classList.remove('dropDown-top');
        if(needToMoveOnTop(el)) {
            el.top = newTopValue;
            el.right = newRightValue;
            el.classList.add('dropDown-top');
        }
    },
    render() {
        let dataFeed = this.props.dataFeed;
        return (
            <DropDown >
                {dataFeed.map((data, i) => {
                    return (<DropDownRow key={response.symbol} data={data}/>);
                })}
            </DropDown>
        );
    }
});

そして、ここにsetstateのコードがあります(無限ループを作成します)

let SearchDropdown = React.createClass({
    getInitialState() {
        return {
            top: false
        };
    },
    componentDidUpdate(params) {
        let el = this.getDOMNode();
        if (this.state.top) {
           this.setState({top: false});
        }
        if(needToMoveOnTop(el)) {
            el.top = newTopValue;
            el.right = newRightValue;
            if (!this.state.top) {
              this.setState({top: true});
           }
        }
    },
    render() {
        let dataFeed = this.props.dataFeed;
        let class = cx({'dropDown-top' : this.state.top});
        return (
            <DropDown className={class} >
                {dataFeed.map((data, i) => {
                    return (<DropDownRow key={response.symbol} data={data}/>);
                })}
            </DropDown>
        );
    }
});
84

setStateinside componentDidUpdateを使用できます。問題は、ブレーク条件がないため、どういうわけか無限ループを作成していることです。

コンポーネントがレンダリングされた後、ブラウザによって提供される値が必要であるという事実に基づいて、componentDidUpdateの使用に関するあなたのアプローチは正しいと思います。それは、setState

83
damianmr

setState内でcomponentDidUpdateを使用すると、コンポーネントが更新され、その後componentDidUpdateが呼び出され、その後setStateが再度呼び出され、無限ループが発生します。条件付きでsetStateを呼び出して、呼び出しに違反する条件が最終的に発生することを確認する必要があります。例:

componentDidUpdate: function() {
    if (condition) {
        this.setState({..})
    } else {
        //do something else
    }
}

Propをコンポーネントに送信するだけでコンポーネントを更新する場合(componentDidUpdate内の場合を除き、setStateによって更新されません)、setStateの代わりにcomponentWillReceiveProps内でcomponentDidUpdateを呼び出すことができます。

49
mickeymoon

componentDidUpdateシグネチャはvoid::componentDidUpdate(previousProps, previousState)です。これにより、どの小道具/状態が汚れているかをテストし、それに応じてsetStateを呼び出すことができます。

例:

componentDidUpdate(previousProps, previousState) {
    if (previousProps.data !== this.props.data) {
        this.setState({/*....*/})
    }
}
42
Abdennour TOUMI

状態に既に設定しようとしている値と同じ値があるかどうかを確認する必要があると思います。同じ場合、同じ値に状態を再度設定する必要はありません。

状態を次のように設定してください。

let top = newValue /*true or false*/
if(top !== this.state.top){
    this.setState({top});
}
1
gradosevic

ToolTipを中央に配置する必要がある場合、同様の問題が発生しました。 componentDidUpdateのReact setStateによって無限ループに陥り、動作する状態を試しました。しかし、refコールバックで使用すると、よりシンプルでクリーンなソリューションが得られました.refコールバックにインライン関数を使用すると、コンポーネントの更新ごとにnullの問題に直面します。 refコールバックで関数参照を使用し、そこに状態を設定すると、再レンダリングが開始されます

0
Sanjay