3
4

More than 3 years have passed since last update.

React&Reduxエッセンシャル

Posted at

Redux&Reduxエッセンシャル

まずは,reduce,reducer,state,actionの整理

Reduce,Reducer,State,Actionとは?

reduce -直訳-> 変える
reducer -直訳-> 変化を与えるもの
state -直訳-> 状態
action -直訳-> 実行

定義

Reduceとは,一回あたりの関数適用によって行われる値の変化
Reducerとは,適用される関数の事
Stateとは,reduceされる前の初期状態
Actionとは,stateをどのように変更させるか

例) 関数 F(aを2倍にする処理を行う(Action))

F(2) ->F(a) -Reduce->4

F(2)がState,
F(a)がReducerです.

Redux実践

インポート

import { createStore } from 'redux'

簡単な例

Reducerでは,Actionによって,switch文などでStateに変更を加える

function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}

掲示板を作ろう

目標

JQueryで言うと,

<html>
<form>
<input type="text" id="hoge" />
<button onclick="push()">追加</button>
</form>
<ul id="list"></ul>
</html>

<script>
function push(){
let sentence = $("#hoge").val() ;
$("#list").append("<li>"+sentence+"</li>") ;
}
</script>

スクリーンショット 2020-02-09 9.42.36.png

こんなものをReact&Reduxの基礎を踏まえながら説明.

install

React

npmはインストール済みの環境であることを前提とします.
※してない方は $brew install npm

$ npm install -g create-react-app

スクリーンショット 2020-02-09 9.58.21.png
このようにreactをインストール

プロジェクトの作成

$ create-react-app todo

スクリーンショット 2020-02-09 10.04.54.png

こんな感じのフォルダが出来ると思います.

$ cd todo

todoに移動しましょう.

Redux

$  npm install --save redux react-redux redux-logger

todoフォルダにReduxのインストール
スクリーンショット 2020-02-09 10.09.46.png

これで環境構築は完了.

ディレクトリの作成

actions
components
containers
reducers
というフォルダをsrc下に配置
各フォルダ内にtodo.jsを作成しましょう.

スクリーンショット 2020-02-09 10.14.37.png

また,src下にcreatestore.jsというファイルも作ってください.
スクリーンショット 2020-02-09 10.19.05.png

createstore.jsに関数を作ります

import { createStore as reduxCreateStore, applyMiddleware, combineReducers } from "redux";
import logger from "redux-logger";
import { todoReducer } from "./reducers/todo";

export default function createStore() {
  const store = reduxCreateStore(
    combineReducers({
      todo: todoReducer,
    }),
    applyMiddleware(
      logger,
    )
  );

  return store;
}

ReactにReduxを適用

index.jsを変更します.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from 'react-redux';
import createStore from './createstore';

const store = createStore() ;

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>, 
  document.getElementById('root')
);


// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

redux,createstoreをインポートして,Providerにstoreをセットしてるだけです.

serviceWorker.unregister()とはオフラインでのキャッシュを無効にしてます.
これはcreate-react-appをすると標準でついてます.今は無視してOKです.

Component定義

components/todo.js
todo追加用のテキストボックスとボタンを書き入れます.

import React from 'react';

export default class Todo extends React.Component{
  render(){
    return(
      <div>
        <input type="text" />
        <button>追加</button><br />
        <ul>
          <li>aaa</li>
          <li>bbb</li>
        </ul>
      </div>
    );
  }
}

スクリーンショット 2020-02-09 10.57.26.png

Action定義

actions/todo.js

export const addTodo = (todo) => {
  return {
    type: 'ADD_TODO',
    payload: { todo: todo }
  };
}

Actionは、Reducerに指令を出します。
type プロパティを必ず持ち、これが処理のキーになります。

payload プロパティは、処理に使うパラメータで、この例では追加するTODOを持たせています

Reducer定義

reducer.todo.js

const initialState = {
  todoList: []
}

export const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      // 新しく追加するTODO
      const todo = action.payload.todo;
      // stateを複製して追加
      const newState = Object.assign({}, state);
      newState.todoList.push(todo);
      return newState;
    default:
      return state;
  }
};

state は書き換えるのではなく新たなオブジェクトとするのがredux.

単純に引数のstateに追加するのではなく、

Object.assignメソッドで複製した新たな state に対して追加し、
それを戻り値とします。

Componentの定義

components/todo.js

import { connect } from 'react-redux';
import * as actions from '../actions/todo';
import Todo from '../components/todo';

const mapStateToProps = state => {
  return {
    todo: state.todo,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    addTodo: (todo) => dispatch(actions.addTodo(todo)),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Todo)

mapStateToProps関数
使用する state を切り出して、propsで参照できるようにするための関数

mapDispatchToProps関数
dispatchするための関数をpropsにマッピングするための関数

それぞれ定義したものを、connect関数でコンポーネントに接続し、exportします。こうすることで、コンポーネントがreduxによる状態管理を意識せず、stateやdispatchを参照、実行できるようになります。

コンテナの使い方は、コンポーネントをimportしている箇所をコンテナに切り替えるのみ。
app.js

import React, { Component } from 'react';
import './App.css';
//import Todo from './components/todo';
import Todo from './containers/todo';

Componentの書き換え

components/todo.js

import React from 'react';

export default class Todo extends React.Component {
  state = {
    todo: ''
  }

  render() {
    console.log(this.props);

    // StoreのTodoからリストを生成
    const list = this.props.todo.todoList.map((todo, index) => <li key={index}>{todo}</li>)

    return (
      <div>
        <input type="text" onChange={elm => this.setState({ todo: elm.target.value })} />
        <button onClick={() => this.props.addTodo(this.state.todo)}>追加</button><br />
        <ul>
          {list}
        </ul>
      </div>
    );
  }
}

スクリーンショット 2020-02-09 11.25.34.png

冗長なコードになればなるほどreduxの恩恵が大きいです.
変更点がすぐに分かるので,チームでの開発が従来よりも簡単.

3
4
0

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
3
4