

こんにちは。  
React の props 更新に対しての再描画処理について  
よい実装について教えてください。

次のサンプルを作りました。  
私には動きそうに見えたのですが動きませんでした。

問題は、グローバルに定義した `counterCount` の値は修正されるのですが  
それに応じて コンポーネント内の `this.props.count` が更新されない  
というものです。

これを改善するにはどのようにしたらよいのでしょうか？

[code]

    this.forceUpdate();
    
[/code]

をコメントアウトしていますが、コメントアウト解除しても症状変わりませんでした。

おそらくですが `<Counter>` コンポーネントを、親というか上位コンポーネントで囲って  
そこのstateを `setState` で変えればいい、というのはわかっているのですが  
それしか手がないものでしょうか？

Reactってそういうもの？

あるいは、なにか再描画処理を行うメソッドがあったり、 `forceUpdate` の指定箇所が違うとか。

ご存知の方おられましたら教えてください。  
よろしくお願いします。

[code]

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>test</title>
      </head>
      <body>
        <div id="content"></div>
        <script src="https://unpkg.com/react@15/dist/react.js"></script>
        <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.2/react-redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.19.0/babel.min.js"></script>
        <link rel="stylesheet" type="text/css" href="style.css">
    
        <script type="text/babel">
    
    var Counter = React.createClass({
    
      handlePlus: function () {
        this.props.onClickPlus();
        console.log(this.props.count);
        // this.forceUpdate();
      },
    
      handleMinus: function () {
        this.props.onClickMinus();
        console.log(this.props.count);
        // this.forceUpdate();
      },
    
      render: function () {
        return (
          <div>
            <h3>
              {this.props.name}の個数
        </h3>
            <button onClick={this.handlePlus}>
              プラス！
        </button>
            <div>{this.props.count}個</div>
            <button onClick={this.handleMinus}>
              マイナス！
        </button>
          </div>
        );
      }
    })
    
    var counterCount = 5;
    
    var handlePlus = function () {
      console.log('handlePlus', counterCount);
      counterCount += 1;
    };
    
    var handleMinus = function () {
      console.log('handleMinus', counterCount);
      counterCount -= 1;
    };
    
    var counters = (
      <div>
        <Counter 
          name="りんご" 
          count={counterCount}
          onClickPlus={handlePlus}
          onClickMinus={handleMinus}
        />
      </div>
    );
    
    var content = document.getElementById('content');
    ReactDOM.render(counters, content);
    
        </script>
      </body>
    </html>
    
[/code]

サンプルの元は下記ページのものです。  
ページ内のサンプルは正しく動きますが  
stateフルなコンポーネントになっています。

ブラウザだけでできるReact・Reduxチュートリアル - Qiita  
<https://qiita.com/paddy-oti/items/d2fd896627ecf0b466be>


CC BY-SA 4.0
2019-12-19T03:25:24.010
61564
2020-04-28T21:36:39.263
2019-12-25T03:06:55.127
32986
21047
question
reactjs
ReactのPropsに渡された時の再描画についての疑問


親(上位)のコンポーネントのstateで管理するやり方で実装してみました。  
statelessコンポーネントで実装しようとしても、上位のどこかでは stateフルにしないといけない、ということなんですかね...

このあたりの知見、お持ちの方おられましたらアドバイスや  
よいリンク先紹介など、いただけたら助かります。

[code]

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>test</title>
      </head>
      <body>
        <div id="content"></div>
        <script src="https://unpkg.com/react@15/dist/react.js"></script>
        <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.2/react-redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.19.0/babel.min.js"></script>
        <link rel="stylesheet" type="text/css" href="style.css">
    
        <script type="text/babel">
    
    var Counter = React.createClass({
      render: function () {
        return (
          <div>
            <h3>
              {this.props.name}の個数
        </h3>
            <button onClick={this.props.onClickPlus}>
              プラス！
        </button>
            <div>{this.props.count}個</div>
            <button onClick={this.props.onClickMinus}>
              マイナス！
        </button>
          </div>
        );
      }
    })
    
    var CounterParent = React.createClass({
    
      getInitialState: function () {
        return { counterCount: 5 };
      },
    
      handlePlus: function () {
        this.setState(
          { counterCount: this.state.counterCount + 1 }
        );
      },
    
      handleMinus: function () {
        this.setState(
          { counterCount: this.state.counterCount - 1 }
        );
      },
    
      render: function () {
        return (
          <div>
            <Counter
              name="りんご"
              count={this.state.counterCount}
              onClickPlus={this.handlePlus}
              onClickMinus={this.handleMinus}
            />
          </div>
        )
      }
    });
    
    var content = document.getElementById('content');
    ReactDOM.render((<CounterParent />), content);
    
        </script>
      </body>
    </html>
    
[/code]


CC BY-SA 4.0
2019-12-19T03:52:41.213
61566
2019-12-19T03:52:41.213
21047
61564
answer


こんにちは、s.yamamotoさん

実装については、1つ目の回答で書かれている「親(上位)のコンポーネントのstateで管理するやり方」で、問題ないと思います。

> statelessコンポーネントで実装しようとしても、上位のどこかでは stateフルにしないといけない、ということなんですかね...

上記コメントは仰るとおりです。子コンポーネントをstatelessにしたとしても、Reactコンポーネントを構成しているどこかでstateを保持する必要があります。これはReduxなどの状態管理ライブラリを利用し、Reactのコンテキスト外にデータを保持する構成だったとしても、状態を利用するためにはReactコンポーネントを利用する際に、Reduxが保持している状態とReactコンポーネントをconnectすることになるので、結果としては、Reactコンポーネントがstateを保持していることになります。

Reactの初期段階は、Facebookのコメント機能を実装するために作られたという話を聞いたことがあるのですが、UIレベルで振る舞いとデータを囲い込み、そのコンテキスト内で完結できるような思想のはずです。  
その観点については、以下のリンクで公式に述べられています。

<https://ja.reactjs.org/docs/thinking-in-react.html>

以上、参考になれば、幸いです。


CC BY-SA 4.0
2019-12-25T00:12:31.543
61750
2019-12-25T00:12:31.543
37156
61564
answer


> Reactってそういうもの？

については、(ステートフルがどうこうというより、)更新処理のパラダイムについて誤解しているかと考えます。  
React環境において描画更新要求を行うのはプログラマではなくReactフレームワークです。  
プログラマが行うのはプログラム内で管理している状態の更新です。

プログラマが描画に関わる状態を更新した場合、Reactフレームワークがそれを検知して描画更新を行う、というのが処理の流れです。  
ですのでプログラマが明示的に描画更新要求を行う[`forceUpdate()`は一般的に利用を避けるべき](https://ja.reactjs.org/docs/react-
component.html#forceupdate)ということになります。

* * *

質問のコードについては、 `counterCount` を参照しているコンポーネント(ここでは`Counters`)に対して `forceUpdate()`
する必要があります。

[code]

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>test</title>
      </head>
      <body>
        <div id="content"></div>
        <script src="https://unpkg.com/react@15/dist/react.js"></script>
        <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.2/react-redux.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.19.0/babel.min.js"></script>
        <link rel="stylesheet" type="text/css" href="style.css">
    
        <script type="text/babel">
    
    var Counter = React.createClass({
    
      handlePlus: function () {
        this.props.onClickPlus();
        console.log(this.props.count);
        // this.forceUpdate();
      },
    
      handleMinus: function () {
        this.props.onClickMinus();
        console.log(this.props.count);
        // this.forceUpdate();
      },
    
      render: function () {
        return (
          <div>
            <h3>
              {this.props.name}の個数
        </h3>
            <button onClick={this.handlePlus}>
              プラス！
        </button>
            <div>{this.props.count}個</div>
            <button onClick={this.handleMinus}>
              マイナス！
        </button>
          </div>
        );
      }
    })
    
    var counterCount = 5;
    
    var handlePlus = function () {
      console.log('handlePlus', counterCount);
      counterCount += 1;
    };
    
    var handleMinus = function () {
      console.log('handleMinus', counterCount);
      counterCount -= 1;
    };
    
    var Counters = React.createClass({
      update: function() {this.forceUpdate();},
    
      render: function () {
        return (
          <div>
            <Counter 
              name="りんご" 
              count={counterCount}
              onClickPlus={() => {handlePlus();this.update();}}
              onClickMinus={() => {handleMinus();this.update();}}
            />
          </div>
        );
      }
    })
    
    var content = document.getElementById('content');
    ReactDOM.render(<Counters />, content);
    
        </script>
      </body>
    </html>
[/code]


CC BY-SA 4.0
2020-04-28T21:36:39.263
66087
2020-04-28T21:36:39.263
2808
61564
answer