Reactのなにが「宣言的」なのか

Reactの公式サイトのトップに謳われている3つの特徴、

  • Declarative
  • Component-Based
  • Learn Once, Write Anywhere

のうち、

  • Declarative(宣言的である)

とは、どういうことか、jqueryにどっぷり浸かっていた筆者がもやもやと考えていた過程を記します。

最初に結論

ReactではUIの部品に対し、「アプリの内部状態がこの状態だったら、この見た目(表示)になるべし」と宣言するように実装してゆきます。なので、「宣言的であると」特徴付けられています。

この実装方法と、Reactのもう一つの特徴である「Component-Based」と組み合わせることで、Reactはページデザインからのシームレスな設計実装や、実装にたいするデバッグの容易性を実現しているそうです。

jquery

jqueryでは、viewが別に提供されていて、そのviewの要素に対するアクションをトリガーに、「どういった処理をするか」を記述します。「どういった処理をするか」にはアプリケーションの状態更新もあれば、viewの見た目の更新もあります。

$("#btn-hoge").click(function(){xxx});

jqueryは、いわば変化を実装するフレームワークであり、宣言的に対して命令的と表現されることもあります。

function(){xxx}は、#btn-hogeクリック時に即座に実行されます。したがってxxx部分に何らかのviewの更新があったら、#btn-hogeクリックのタイミングで更新が発生します。

一方、Reactでは、コンポーネントの見た目を、render()という、フレームワーク上で規約されたメソッドで定義します。

render() { return ( <div> <Child data={this.state.value1} handleClick={this.handleClick} /> </div> ); }

宣言型プログラミング

1970年代頃、Prologというプログラミング言語がありました。これは論理プログラミング言語とも呼ばれており、自然言語処理やAIといった分野で使われています。(未だ現役かは不明)

Prologの特徴として、「純粋にロジックを記述する」という点があります。プログラミングとは、本来ロジック(論理)を記述するものであり、それをどういった手続きで実行するか(命令するか)については、実行する側が担うべき課題である、という考えに立っています。

この「記述する側」と「実行する側」を、「Reactで実装する側」と「Reactフレームワーク側」に置き換えると、宣言的であるという意味合いの理解が深まります。

Reactでは、コンポーネントの状態を実装する側が直接更新することを禁止しています。代わりに、コピーした状態を更新し、setStateメソッドを呼びます。

handleClick(i) {
  console.log(this.state);
  var history = this.state.history.slice(0, this.state.stepNumber + 1);
  const current = history[this.state.stepNumber];
  const squares = current.squares.slice();
  if (calculateWinner(squares) || squares[i]) {
    return;
  }
  squares[i] = this.state.xIsNext ? 'X' : 'O';
  this.setState({
    history: history.concat([{
    squares: squares
  }]),
  stepNumber: history.length,
  xIsNext: !this.state.xIsNext,
});
}
また、先のrender()にあるように、実装側は、状態と見た目の組み合わせをReact側に伝えるだけで、実際に画面の更新を命令することはありません。

以上により、Reactによる開発では、状態の更新タイミングと、画面の更新のタイミングについては、実装側は宣言をするのみで、実現はReactが請け負うという枠組みになっていることが言えます。

「俺はこうなって欲しいんだ。だから、よしなにやってくれ」

という感じでしょうかね。