LoginSignup
2
0

More than 3 years have passed since last update.

storeを実装してJavaScriptへの理解を深める

Last updated at Posted at 2019-06-17

es6 の module import/export の仕様を再確認したかったのが出発点。

準備

手軽なのでcreate-react-appを利用する。

create-react-app mystore
cd mystore

store実装

store.js
export let globalState = { count: 1 }
export const increment = () => {
  globalState = { count: globalState.count + 1 }
}

変数とその変更方法を提供してるだけ
これを複数箇所からimportして利用する。

App.js
import React from 'react';
import './App.css';
import { globalState, increment } from './store'
import Counter from './Counter'

class App extends React.Component {
  state = { count: globalState.count }

  increment = () => {
    increment()
    this.setState({ count: globalState.count })
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <h2>Parent counter</h2>
          <p>{globalState.count}</p>
          <button onClick={this.increment}>increment</button>
          <Counter />
        </header>
      </div>
    );
  }
}

export default App;

component の stateを利用してないのはご愛嬌。
(値を直接見たかったので。再描画用のsetState)。

Counter.js

import React from 'react'
import { globalState, increment } from './store'

class Counter extends React.Component {
  state = { count: globalState.count }

  increment = () => {
    increment()
    this.setState({ count: globalState.count })
  }

  render() {
    return (
      <div>
        <h2>Child counter</h2>
        <p>{globalState.count}</p>
        <button onClick={this.increment}>increment</button>
      </div>
    )
  }
}

export default Counter

ポイント:

  • export されている値が変更されたら、その変更はimport先のファイルをまたいで維持される(この例でも、リアルタイムに描画されるかはともかく、親と子で最終的には値が同期されている)
  • リアルタイムに再描画されない場合がある
    • この例では子での変更は親に反映されない
    • 親の方のボタンをクリックしたら同期される

subscription 機能を実装

値をリアルタイムに同期させたいなら起点となるイベントが必要だということだろう。
subscription用のコールバックを格納する配列を作って変更のたびに全て実行する。

store.js
const subscriptions = []
export const addSubscription = (callback) => {
  subscriptions.push(callback)
}
export let globalState = { count: 1 }

export const subscribedIncrement = () => {
  globalState = { count: globalState.count + 1 }
  subscriptions.forEach(callback => callback(globalState))
  // console.log(subscriptions)
}

コンポーネントのコンストラクタあたりでコールバック追加すれば良い。

App.js
// ...

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { count: globalState.count }
    addSubscription(this.onGlobalStateChange)
  }

  increment = () => {
    subscribedIncrement()
    this.setState({ count: globalState.count })
  }

  onGlobalStateChange = (globalState) => {
    this.setState(globalState)
  }
// ...

解除方法は知らぬ。

結論

  • Reduxで良い
  • ただし、React Reduxは何が嬉しいのだったか頭を整理中
    • propsに渡すパターン?
    • コンテナコンポーネント作るならいらん?
2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0