Posted on: Written by: K-Sato
⚠️ This article was posted over 2 years ago. The information might be outdated. ⚠️

Table of Contents

Introduction

基本概念

Redux は以下の3で成り立つ。

State

state はセッターのないモデルのようなもの。

Action

actionを使用する事のみでstateの内容を変更できる。 actionはただの JavaScript のオブジェクト。

Reducer

reduceractionstateを結びつけるもの。 reducerstate actionを引数に取り、次のstateの状態を返す単なるファンクション。

3 つの原則

Single source of truth

アプリのすべてのstateは1つのstoreに集約する。

State is read-only

stateは単純なオブジェクトであるactionを使用してのみでしか変更を行わない。

Changes are made with pure functions

reducerは純粋なファンクションであり、与えられた値を変更するのではなく、必ず新しい値を返す。

Basics

Actions

actionは、アプリケーションからstoreにデータを送信する情報のペイロードです。store.dispatch()storeに送ることが可能。

todo にアイテムを加えるアクションの例

{
  type: ADD_TODO
  text: 'Build my first Redux app'
}

actionsは JS の単純なオブジェクトで,必ず使用されるactionを示すtypeプロパティをもつ。

Action Creators

Action Creatorsはその名の通り、actionを作り出す関数である。 Redux ではAction Creatorsactionオブジェクトを返す。

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

その他の actionsCreators と VisibilityFilters

export function addTodo(text) {
  return { type: ADD_TODO, text }
}

export function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

export function setVisibilityFilter(filter) {
  return { type: SET_VISIBILITY_FILTER, filter }
}

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
}

Reducers

Reducers 基本

Reducersstoreに送られたactionに応じてstateがどのように変更するのかを示す。

reducerstate actionを引数に取り、次のstateの状態を返す単なるファンクション。

(previousState, action) => newState

stateの構造の例

  • The currently selected visibility filter
  • The actual list of todos.
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}

Reducerが純粋は関数であることは重要であり、下記の事はしてはならない。

  • Mutate its arguments.
  • Perform side effects like API calls and routing transitions.
  • Call non-pure functions(e.g. Date.now() or Math.random().)

Reducerを作成する

最初の state を作成し、reducerに与える。 引数の値は変更せずにobject.assign(target, ...sources)を利用する事でコピーを作成し、新しいオブジェクトを返すようにする。または2つ目の例のようにObject Spread Operatorを使用する事で同様の事を行える。

defaultでは元のstateを返すように設定する事で、不明なactionに対しては元の状態を返す。

const initialState = {
  visibilityFilter: VisibilityFilters.SHOW_ALL,
  todos: []
}

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return object.assign({}, state, {
        visibilityFilter: action.fiter
      })
    default:
      return state
  }
}

//上の関数と同様だがObject Spread Operatorを使用
function todoApp(state = initialState, action) {
  switch(action.type) {
    case SET_VISIBILITY_FILTER:
      return {
        ...state,
        visibilityFilter: action.filter
      }
    default:
      return state
  }
}

やってることとしては以下のように...stateで開いて中身の値に新しい要素を加えて新しい値として返してるだけ。

const initialState = {
  todos: [1,2,3]
}

console.log(...initialState.todos, 4)

更に actions を付け加える

function todoApp(state = initialState, action) {
  switch(action.type){
    case SET_VISIBILITY_FLITER:
      return {
        ...state,
        visibilityFilter: action.filter
      }
    case ADD_TODO:
      return {
        ...state.todos,
        {
          text: action.text,
          completed: false
        }
      }
    default:
      return state
  }
}

Store

storeは以下の為に存在する。

  • Holds application state;
  • Allows access to state via getState();
  • Allows state to be updated via dispatch(action);
  • Registers listeners via subscribe(listener);
  • Handles unregistering of listeners via the function returned by subscribe(listener) 1 つの Redux アプリに関して 1 つのstoreだけが存在する。 様々なデータを扱う際にはreducerを細分化する事で対応する。

reducerがあればのstoreの作成は簡単で、以下のようにできる。

import { createStore } from 'redux'
import todoApp from './reducers'

const store = createStore(todoApp)

アクションを送る。

以下のようにアプリのstateの値を獲得したり、変更したりできる。

import {
  addTodo,
  toggleTodo,
  setVisibilityFilter,
  VisibilityFilters
} from './actions'

// Log the initial state
console.log(store.getState())

// Every time the state changes, log it
// Note that subscribe() returns a function for unregistering the listener
const unsubscribe = store.subscribe(() => console.log(store.getState()))

// Dispatch some actions
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))

// Stop listening to state updates
unsubscribe()

Usage with React

Installing React-Redux

以下のように react-redux をインストールする。

$ npm install --save react-redux

Presentational and Container Componensts

Reactは view を扱うライブラリでありReduxが有するstoreActionの情報と疎結合になっていることが好ましい。

Container Components

ReduxstoreActionを受け取りReactコンポーネントのPropsとして渡す役割を担う。(= React と Redux の橋渡し。JSX は使用しない。)

Presentational Components

Redux依存のない純粋な React コンポーネント。

About the author

I am a web-developer based somewhere on earth. I primarily code in TypeScript, Go and Ruby at work. React, RoR and Gin are my go-to Frameworks.