ウェブ開発ではブラウザのJS処理やロジックが複雑になってしまうときがありますね。
そんな時は、Reactを使ってシンプルにしてみましょう。

Reactの公式サイト https://reactjs.org/

コンポーネントを作成する

まずReactで`コンポーネント`を作成したいときは以下のように定義します。

import ...
export default class OrderDetailList extends Component {
  constructor(props) {
    super(props)

    this.store = {...}
    this.state = {...}
  }

  render() {
    return (
      ...
    )
  }
}

`Store`は状態を保管しておくものです。`Store`の値を変更しても`View`は何も変わりません。
一方、`State`も状態を保管しておくものですが、`Store`の値が変更されると、それに連動して`View`も変更されます。

`State`の値を変更したいときは`setState`のメソッドを使用します。 (https://reactjs.org/docs/react-component.html#setstate)

例えば、以下の`コンポーネント`があります。

import ...
export default class OrderDetailList extends Component {
  constructor(props) {
    super(props)

    this.state = {
      name: this.props.name
    }
  }

  onClickChangeName() {
    this.setState({name: "New name"})
  }

  render() {
    return (
      <div onClick={() => this.onClickChangeName()}>
        {this.state.name}
      </div>
    )
  }
}

上記の`コンポーネント`の`onClickChangeName`の中に`State`の`name`の値を変更するため`setState`メソッドを使用して、`State`の`name`の値が変更される同時に`View`の`name`の値も変更されます。

コンポーネントのStateを変更する

`コンポーネント`内の`State`を変更するのは上記のように簡単ですが、別の`コンポーネント`の`State`を変更したい場合はどうするのがよいでしょうか。
例えば`order`リストがあって、1つの`order`の`name`が変更されるとき全体に`name`が変更される`order`を出力する機能があります。その機能を実装してみましょう。

まずは各コンポーネントを定義します。

`ListOrder`コンポーネント:

import ...
import OrderDetail from ...
import OrderStore from ...

export default ListOrder extends Component {
  constructor(props) {
    super(props)

    OrderStore.orders = this.props.orders

    this.state = {
      orders: OrderStore.all.orders,
      changed_count: 0
    }
  }

  renderListOrder() {
    const list = this.state.orders.map((order) => {
    return(<OrderDetail key={order.id} order={order}>)
    })
  }

  componentDidMount() {
    OrderStore.addListener(() => this.setState(OrderStore.all))
  }

  render() {
    return (
      <div>
        {this.state.unchange_count}
        {this.renderListOrder}
      </div>
    )
  }
}

OrderDetail`コンポーネント`:

import ...
import OrderAction from ...

export default OrderDetail extends Component {
  constructor(props) {
    super(props)

    this.state = {
      order: this.props.order
    }
  }

  onClickChangeName() {
    OrderAction.changeName(this.props.order)
  }

  render() {
    return (
      <div onClick={() => this.onClickChangeName()}>
        {this.state.order.name}
      </div>
    )
  }
}

次に`OrderStore`という`EventEmitter`を定義します。

import {EventEmitter} from ...
import Dispatcher from ...

class OrderStore extends EventEmitter {
  constructor(Dispater) {
    super()

    this.store = {
      orders: null,
      changed_count: 0
    }

    this.dispatchToken = Dispatcher.register((action) => {
      if (action.type === "ChangeName") {
        order = _.find(this.store.orders, 'id', action.order.id)
        order.name = "New Name"
        this.store.changed_count++

        this.emit("ChangeOrders")
      }
    })
  }

  get all() {
    return this.store
  }

  addListener(callback) {
    this.on("ChangeOrders", callback)
  }
}

最後に`OrderAction`の`Const`を定義します。

import Dispatcher from ...

export const OrderAction = {
  changeName(order) {
    Dispatcher.dispatch({
      type: "ChangeName",
      order: order
    })
  }
}

`OrderList`の`componentDidMount()`の中に`OrderStore.addListener(() => this.setState(OrderStore.all)`を追加しましたので、`OrrderStore`に何かの変更があったらコールバック関数が呼ばれて`Store`の`orders`の値を`State`の値に適用します。そのため、`OrderDetail`のコンポーネントに`name`が変更されるとき`OrderDetailList`コンポーネントにも更新されます。

Reactを活用すれば、複雑の処理やロジックを簡単に実装できます。
みんなさんもReactを使ってみてくださいね。