Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ReduxのサンプルのTodoリストを真似てみる。Part.2

More than 1 year has passed since last update.

ReduxのサンプルのTodoリストを真似てみる。Part.1の続きです。

0.留意点

  • Redux ExampleのTodo Listをはじめからていねいに(1)を参考にさせて頂いて、Reduxのコードを書いた。
  • 初心者の覚書です。
  • 自分の環境で動くように参考にしたコードを適当に修正している。
  • Windows10 64bit , PowerShellなどで動かしている。
  • 見栄えを若干よくする為にbootstrap4を利用している。 #1.Todoの配列でTodoリストを作る

reducersを修正

todoをtodosに変更 stateをtodoの配列にする
ファイル名を reducers/index.jsからreducers/todos.js に変更

reducers/todos.js
const todos = (state=[], action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return {
                ...state,
                id: action.id,
                text: action.text
            }

        default:
            return state;
    }
}
export default todos;

actions/index.jsはあたらしく作り直す。
combineReducers関数を使って、複数のreducers(複数のロジック)をまとめて扱えるようにする。
たとえば、
reducers/hoge.js のなかで、export default hoge
reducers/fuga.js のなかで、export default fuga
し、actions/index.jsで、importして
combineReducers({todos, hoge, fuga})
としておくと、stateオブジェクトのtodosプロパティ、hogeプロパティ、fugaプロパティとしてアクセスできる。この時点ではtodosだけだが、先のことを考えて準備しておく。

reducers/index.js
import todos from './todo'
import { combineReducers }  from 'redux';

const todoApp = combineReducers({todos});
export default todoApp;

コンポーネントをつくる

この辺から、bootstrapを使う。クラス名の指定でできるだけ対応。React、Reduxは関係しない。

コンポーネントの前にまず、ルートのhtmlファイルを修正

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>React,ReduxでTodoリストを作ろう</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  </head>
  <body >
      <!-- classでBootsrapに関する設定 -->
    <div class="mx-auto w-50 mt-3"  id="root"></div>

    <script src="dist/index.js"></script>
  </body>
</html>

Todo一つ一つに対応するTodoコンポーネント

components\Todo.js
import React from 'react';
import PropTypes from 'prop-types';

//classNameでBootsrapに関する設定
const Todo = ({text})=>(
    <li className="list-group-item">{text}</li>
)

Todo.propTypes ={
    text:PropTypes.string.isRequired
}

export default Todo;

複数のTodoコンポーネントを格納するTodoListコンポーネント

components\TodoList.js
import React from 'react';
import PropTypes from 'prop-types';
import Todo from './Todo';

//classNameでBootsrapに関する設定
const TodoList = ({todos})=>(
    <ul className="list-group mx-auto p-3 bg-info rounded" style={{maxWidth:'36rem'}}>
    {todos.map(
        (todo)=>(<Todo key={todo.id} {...todo} />)
    )}
    </ul>
)

TodoList.propTypes = {
    todos: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.number.isRequired,
      text: PropTypes.string.isRequired
    }).isRequired).isRequired
  }

export default TodoList

コンテナでstateとコンポーネントを結びつける

VisibleTodoListコンテナのなかで、state.todosを TodoListのpropsに関連付ける。
そのために、React-Reduxのconnect関数を使う。

containers\VisibleTodoList.js
import React from 'react';
import { connect } from 'react-redux';
import TodoList from '../components/TodoList'


function mapStateToProps(state){
    return {
        todos:state.todos
    }
}

const VisibleTodoList = connect(mapStateToProps)(TodoList);
export default VisibleTodoList;

Appコンポーネントを修正

Appコンポーネントでは、上記のVisibleTodoListコンテナを読み込む。

components\App.js
import React from 'react';
import VisibleTodoList from '../containers/VisibleTodoList'

//classNameでBootsrapに関する設定
const App = () => (
    <div>
    <h1 className="text-center alert alert-info ">Todoリスト</h1>
        <VisibleTodoList />
    </div>
)

export default App;

エントリーポイントのindex.jsを修正

ここまでの変更に合わせて、import関係、モジュール参照名などを修正。

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import todoApp from './reducers'
import { createStore } from 'redux';
import App from './components/App'
import addTodo from './actions'

let store = createStore(todoApp);
store.dispatch(addTodo('Todo 1番目'));
store.dispatch(addTodo('Todo 2番目'));
store.dispatch(addTodo('Todo 3番目'));
store.dispatch(addTodo('Todo 4番目'));
store.dispatch(addTodo('Todo 5番目'));


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

コマンド実行
npm run build
npm run start

http://localhost:8080で動作確認

2018_0528_1351_34.jpg

ソースコード 03

2.Todoの新規追加のフォームをつくる

初めの読み込み時に、input変数にDOMへの参照が格納される。
AddTodo コンポーネントにdispatchを引数で渡す。
新規追加ボタンをクリックすると、コールバックで、ユーザー入力のテキストを用いたactionを引数にしてdispatch関数を実行。

containers\AddTodo.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import addTodo from '../actions/index.js';

let AddTodo = ({ dispatch }) => {
    let input;
    //className,htmlForなどはbootstrapのため
    return (
        <div className="form-group">
            <label htmlFor="todo_name">Todoの名称</label>
            <input type="text" className="form-control" id="todo_name" placeholder="Todoの名称" ref={(node) => { input = node }} />
            <button className="btn btn-primary btn-lg btn-block mt-1" onClick={() => { dispatch(addTodo(input.value)); input.value="" }}>新規追加</button>
        </div>
    )
}
AddTodo = connect()(AddTodo);
export default AddTodo;

Appコンポーネントを修正

components\App.js
import React from 'react';
import VisibleTodoList from '../containers/VisibleTodoList'
import AddTodo from '../containers/AddTodo'

//classNameでBootsrapに関する設定
const App = () => (
    <div>
    <h1 className="text-center alert alert-info ">Todoリスト</h1>
        <VisibleTodoList />
        <AddTodo />
    </div>
)

export default App;

実行結果

2018_0528_1531_46.jpg

ソースコード 04

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away