Help us understand the problem. What is going on with this article?

Web初心者でもモダンなReact, Redux, FirebaseでTo-Doを作る1 ~React~

はじめに

はじめまして。

今年の5月くらいからWebど素人な状態から、キラキラ、お金DrivenでWeb開発のバイトにほぼ未経験で雇ってもらった浅野光平です。

巷ではアサコと呼ばれたりします。

本シリーズの目標は、

を使ってちょっとリッチなTo-Doを作ることです。
完成版はこちらです

想定読者ははじめの僕を想定してWeb界隈初心者だけどプログラミングはちょっとやったことあって、みたいな学生(くらいな若者)をイメージして書きます。基本的には、Reduxの公式Tutorialをちょっといじる感じです。作ったあとに、Travis CIJestを使って適当にテスト,CI環境も整えてみます。

公式の通りなので、自分で英語読むのが好きな兄貴たちには不要な記事ですが、日本で生きる我々にとってやはり日本語はとっつきやすいのでどこかの誰かの助けになることを願い描きます。

記事のインデックスと内容は

  1. Reactのスケルトン作り←イマここ
  2. Reduxのデータフロー導入
  3. Firebaseを使ってデータベースと認証
    4. Travis, Jestでテスト, CI環境を作る

こんな感じでいきます。

本当に使う人は公式ドキュメントで英語をガリガリ読むべきだと思う派なので、かなり主観的にざっくりと書いていきます。突っ込んでくれる余裕のある方はどんどん突っ込んでいただきたいです。

Reactのイメージ

ReactはFacebook製のNodeライブラリです。

React公式サイトには、特徴として三つ書かれています。

Declarative

命令型ではなく、宣言型です。
ざっくりいうと処理で書くのではなく、そのものの性質で記述するということでしょうか。()
ほとんどそのままHTMLを表現できる(JSX)という意味かもしれません。

命令型プログラミング wiki

宣言型プログラミング wiki

Component-Based

Reactの思想で最も代表的なのがComponentの概念です。
ReactはUIをいくつかの部品(Component)を組み立てたものとして捉え、Componentごとにファイル分割してカプセル化します。

Learn Once, Write Anywhere

Reactを一回学んでしまえば、React NativeというクロスプラットフォームなMobileアプリ開発フレームワークでMobileアプリも作れるようになったりします。

Vue.js

とはいえ僕はReactがJSルネッサンスと呼ばれる現代においてどういう意味を持つのか完全に理解していません。

対抗フレームワークとして有名なのがVue.jsというReactの後追いをして開発が進んでいるもので、Web3言語を使った開発経験がある方だとHTML, CSS, JSをそのままかけるので学習しやすいそうです。(僕は触ったことないです)

0. 環境構築、 create-react-app 

さてそれではとりあえずReactでTo-DoでHello,Worldしてみましょう。

React推奨の開発フローの通り流れは以下の通りで。

  1. 環境構築
  2. 静的なToDoを実装
  3. ToDoの追加と完了(未完化)を実装する

今回はcreate-react-appというまたFacebook製のjsパッケージを使います。Railsのように、CLIでコマンド一発でReactアプリのスケルトン(雛形)を作れる優れものです。

まずReactを使うためにはNode(とnpm)のインストールが必要です。ここでは詳しく描きませんが下記公式Installerか、各Package ManagerでInstallしてください

Node.js

Nodeをインストールしたら下記のコマンドでReactのスケルトンを作りましょう。r-r-f-todo(ReactReduxFirebaseToDo)はアプリの名前です。好きにつけましょう。

npm startでローカルホストが立ち上がって初期状態が見れると思います。

npx create-react-app r-r-f-todo
cd r-r-f-todo
npm start

スクリーンショット 2018-12-01 22.45.02.png

ここで使われているnpxはローカルにInstallしていないパッケージを一回だけ実行しています。

参考

Create a New React App

1. 静的なTo-DoUIの実装

Reduxの公式TutorialをReactだけで書いてみます。
全て関数型のStateless Componentで書かれていますが、一旦Classも使います。

今回はTodoアプリを作ります。UIはこんな感じ(スタイルは読者の創造性におまかせします)

スクリーンショット 2018-12-03 10.59.10.png

Component区分はまるっきり公式のままですが配置を僕の好みにかえます。
今回は

スクリーンショット 2018-12-03 10.55.27.png

  • ToDo: ToDo一つ一つ
  • ToDoList: ToDoをまとめるやつ
  • AddTodo: ToDoを追加する

の3つのComponentを作成し、AppComponentに乗せて、Index.jsでRenderします。
まずいらないテンプレートを消してcomponentsディレクトリを作ります。

cd src
mkdir components
rm App.css App.test.js index.css logo.svg
mv App.js components/
cd components
touch AddTodo.js Todo.js TodoList.js

App.jsを移動したのでIndex.jsのインポート元を変えます

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(<App />, document.getElementById('root'));

次にAppを編集します。各子Componentがあると仮定して、配置と与えるデータを決めます。

今回のTodoのデータは、下記PropertyからなるJavaScriptのオブジェクト

  • id: Todoのインデックス (Number)
  • text: テキスト (string)
  • completed: 完了 or not (bool)

のリストで定義します。

src/components/App.js

import React from 'react'
import AddTodo from './AddTodo'
import TodoList from './TodoList'

class App extends React.Component {
  render(){
    return (
      <div>
        <TodoList todos={[{id: 0, text: "asano", completed: false},{id: 1, text: "kouhei", completed: true}]} />
        <AddTodo />
      </div>
    )
  }
}

export default App

上からTodo本体(TodoList), Todo追加フォームとボタン(AddTodo)の順番で並べます。

Reactは、JSX(JavaScript eXtension)でHTMLを表現します。クラスのComponentはrenderメソッドを定義してあげて、JSXを返させます。

ToDoListには、TodoのデータをRenderしてほしいのでProps(HTMLのattrみたいにComponentに引数として渡せるもの)を渡します。

さて、Componentを実装しましょう。細かいComponentはStateless(関数型) Componentで書くとすっきりかけます。

src/components/Todo.js

import React from 'react'

const Todo = ({ completed, text }) => (
  <li
    style={{
      textDecoration: completed ? 'line-through' : 'none'
    }}
  >
    {text}
  </li>
)

export default Todo

ToDoは、上で定義したJSオブジェクトを受け取って、completedのBoolによって自分に線を引くかどうか(?記法)のスタイルとテキスト本体を持ちます。

src/components/TodoList.js

import React from 'react';
import Todo from './Todo';

const TodoList = ({ todos }) => (
  <ul>
    {todos.map(todo => (
      <Todo key={todo.id} {...todo} />
    ))}
  </ul>
)
export default TodoList

ToDoListは、Todoのデータのリストを受け取って、その数だけToDo Componentを生成します。

src/components/AddTodo.js

import React from 'react';

const AddTodo = () => {
  let input

  return (
    <div>
      <form>
        <input onChange={e => {input = e.target.value}} />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  )
}

export default AddTodo

AddTodoは、公式ではReact Componentのrefを使っていますが、HTMLのInputフォームにしました。

今はonSubmitがないのでボタンを押しても何もおきません

はい!ここまでコピペ(写経)をすれば、静的なTo-Doができます!!

参考

introducing JSX
Rendering Elements
Component and Props

2. Stateを与えて動的にする

動的なページにしましょう。

ReactのClass型のComponentは、StateというMutable(Component内で変更可能)なデータを持たせることができます。
(前に出てきたPropsはImmutableで、Componentで再代入はできません)

次の記事でReduxにState管理は任せますが、今回はReactの独力でState管理をします。

Stateの参考記事を貼る

src/components/App.js

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: [],
      count: 0
     };

  }

  addTodo = (text) => {
    this.setState({
      todos: [...this.state.todos, {
          id: this.state.count,
          text: text,
          completed: false
        }],
      count: this.state.count + 1,
    })
    console.log()
  }

  toggleTodo = (id) => {
    this.setState({
      todos: this.state.todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    })
  }
  render(){
    return (
  <div>
    <TodoList todos={this.state.todos} toggleTodo={this.toggleTodo}/>
    <AddTodo addTodo={this.addTodo}/>
  </div>
    )
  }
}

さてめちゃくちゃコードが増えました、
ComponentにStateを持たせる場合は、Classのコンストラクタで初期化してやって、変更する場合はReact親クラスのメソッドであるsetState()を使って変更します。

setStateは実行されるごとにJSXからHTMLへのRenderの再呼び出しも行ってくれるので、これでViewを変えることができます。

さあ親Componentで渡したPropsに合わせて子Componentを変更しましょう。
HTMLと同じようにonClick, onSubmit(HTMLはonclick, onsubmit)に引数として受け取ったCallback関数を渡しましょう。

Todo

import React from 'react'

const Todo = ({ onClick, completed, text }) => (
  <li
    onClick={onClick}
    style={{
      textDecoration: completed ? 'line-through' : 'none'
    }}
  >
    {text}
  </li>
)

export default Todo

TodoList

import React from 'react';
import Todo from './Todo';

const TodoList = ({ todos , toggleTodo }) => (
  <ul>
    {todos.map(todo => (
      <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
    ))}
  </ul>
)
export default TodoList

AddTodo

import React from 'react';

const AddTodo = ({addTodo}) => {
  let input

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault()
          if (!input) {
            return
          }
          addTodo(input);
          input = '';
        }}
      >
        <input onChange={e => {input = e.target.value}} />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  )
}
export default AddTodo

参考

State lifecycle
Handling Events
Conditional Rendering

次に

さてReactで動的なページが作れたはずですが、こんなしょぼいTodoではなくもっとStateが増えたり、もっと関数が増えたりした時にState管理を統制してくれるのがReduxです。ほんとうはもっと大規模開発の宗教的なもので、なんでもかんでも導入すべきでないという作者の記事もありますが、今回はWeb界隈の関数型の流行を感じるという目的で

次はRedux公式Tutorialの形に持っていきます!多分完成系は公式Tutorialと変わりませんが、Reduxは関数型でなじむのに時間がかかると思うのでそれを補助する勘所なんかを書いていきます!

Why do not you register as a user and use Qiita more conveniently?
  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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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