JavaScript
memo

javasctipt まとめ

event.preventDefaultの使い方

  • クリックなどのイベントは、子要素から親要素へ伝播する(バブリング)
  • preventDefault()はその要素のイベントをキャンセルし、stopPropagation()は親要素への伝播をキャンセルする
  • return false;を使うと、その要素のイベントも親要素への伝播も両方キャンセルする

参考
参考2 具体例

ここでのpreventDefault()は画面の更新ができないようにしている

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case 'HELLO_WORLD':
      return {
        ...state,
        hello: action.hello
      };

    default:
      return state
  }
}

state=initialStateはデフォルト引数
...stateは不明。多分可変長引数的なやつ?

[JS]オブジェクトの分割導入

imageには現在の状態を代入します。
この let {var} = this.obj という書き方はオブジェクトの分割代入という構文で、this.stateimage というプロパティが自動的に let image にセットされます。

困っていること

reactnativeでのフォームの実装の仕方がわからない
=>redux-formを使うことで解決を図っている

tcomb-form-nativeを結局使うことに

今後の設計

現状の課題

Tabはコンポーネントでないためpropsstateを渡すことができない!どうしよう...

reduxの概念

reduxを用いればSPAはmodelのような形で実装できる。ただし、setterを持たない。

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

そこで、actionを通してstateを変更する。
actionはプレーンなjavascript.

reduceractionstateを結びつける概念。
actionとstateを引数にとり、変更後のstateを返す関数という形で実装される。

大きいappを作る際にそういう関数(reducer)を書くのは至難なので、stateの一部を変更する関数を書く。

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([{ text: action.text, completed: false }])
    case 'TOGGLE_TODO':
      return state.map(
        (todo, index) =>
          action.index === index
            ? { text: todo.text, completed: !todo.completed }
            : todo
      )
    default:
      return state
  }
}

以上二つのreducerを用いて対応するstateのkeyから全てのstateを変更する新しいreducerを書く。

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}

全てのstateはstoreに含まれる。

storeの役割

This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra coding effort

とのこと。
全てのstateがstoreに含まれていれば、今まで困難だったUndo/Redoが簡単に実装できるようになる

console.log(store.getState())

/* Prints
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
*/

stateは読み込み専用

stateを更新する方法はただ一つ。何が起こったか示すオブジェクトであるactionを使うこと
このおかげで、viewやコールバックはstateを直接変更できない。その代わり、どのstateを変更したいかということを表明することができる。そして厳密な順序で一つ一つ処理が実行される。actionsはプレーンなオブジェクトのため、ログや再現やデバッグが容易となる。

pure reducerを書いてみればstate treeがいかにactionによって更新されるかが見て取れる。
reducerは前のstateを変更するのではなく、新しいstateを返すものだということには留意したい。

Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state. You can start with a single reducer, and as your app grows, split it off into smaller reducers that manage specific parts of the state tree. Because reducers are just functions, you can control the order in which they are called, pass additional data, or even make reusable reducers for common tasks such as pagination.

function visibilityFilter(state = 'SHOW_ALL', action) {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}

import { combineReducers, createStore } from 'redux'
const reducer = combineReducers({ visibilityFilter, todos })
const store = createStore(reducer)

Action

actionはappからstoreにデータを送る唯一の手段。store.dispatch()でデータを送る。
新しくTodoを追加するアクションを以下に示す。

const ADD_TODO = 'ADD_TODO'

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

actionはプレーンなjavascriptのObject。どのようなアクションが実行されるかを示すtypeをもつ。
type以外のactionの構成は自由だ

Note on Boilerplate
You don't have to define action type constants in a separate file, or even to define them at all. For a small project, it might be easier to just use string literals for action types. However, there are some benefits to explicitly declaring constants in larger codebases. Read Reducing Boilerplate for more practical tips on keeping your codebase clean.

Ajaxの復習をしよう

object spread syntax

array spread operatorと同じで、オブジェクトを展開する。
本番環境ではbabelが必要だがReact Nativeでは安全に使用可能
参考

combineReducers()

以下の二つは同じ

import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

export default function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

store

何を起こったかを示すaction
actionに基づいてstateを変更するreducer
それらを合わせるものがstore

storeの役割

  • appのstateを保持する
  • getState()経由でstateへのアクセスを許可する
  • dispatch(action)経由でstateの更新を許可する
  • subscribe(listener)でリスナーを登録する
  • subscribe(listener)の戻り値に基づいてリスナーの登録解除を行う

storeはappに1つのみ。データ処理のロジックを分割したいときはreducer compositionを用いる

combineReducers()createStore()に渡すことで簡単にstoreを実装することができる

import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp)

データフロー

containerとpresentationalコンポーネント

presentationalコンポーネント

  • 見た目に関連している
  • presentationalとcontainerの両方を内部的に含みうる。また、普通DOMのマークアップとスタイルを保持する
  • this.props.childrenを経由してしばしば抑制(containment)を許可する。
  • actionやstoreなど、appの残りの部分への依存がない
  • どのようにデータがロードされ変更されるのかは特定しない
  • propsのみからデータとコールバックを受け取る
  • ほとんど自身のstateを持たない。持つときはデータではなくUIのstate
  • 関数コンポーネントである


Page, Sidebar, Story, UserInfo, List

containerコンポーネント

  • どのように要素が働くかに関連する
  • presentationalとcontainerの両方を内部にもつが、wrapping divをのぞいてDOMのマークアップを持つことはない。
  • データと振る舞いを他のpresentational/containerコンポーネントに渡す
  • fluxアクションを呼ぶ。また、それらをコールバックとしてpresentationalコンポーネントに渡す
  • 結構ステートフル。データの源として使われがち
  • 通常スクラッチで実装されるというよりreact reduxのconnect()のような上位のコンポーネントからによって生成される


UserPage, FollowersSidebar, StoryContainer, FollowedUserList.

Todoリストを作るときのreact, reduxの構成

react-reduxはpresentational, containerの構成に従う

presentational

reduxの実装

To use connect(), you need to define a special function called mapStateToProps that tells how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping. For example, VisibleTodoList needs to calculate todos to pass to the TodoList, so we define a function that filters the state.todos according to the state.visibilityFilter, and use it in its mapStateToProps:

connect()を使うためには、mapStateToPropsと呼ばれる特別な関数が必要である。それは、どのように現在のstoreが,wrapしているpresentationalコンポーネントに渡すpropsに変更するかを示す.
例えば、VisibleTodoListはTodoListに渡すためにtodosを計算する必要がある。だから我々はstate.visibilityFilterにもとづいてstate.todosをフィルターにかける関数を定義し、mapStateToPropsの中で使用する。

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    case 'SHOW_ALL':
    default:
      return todos
  }
}

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

In addition to reading the state, container components can dispatch actions. In a similar fashion, you can define a function called mapDispatchToProps() that receives the dispatch() method and returns callback props that you want to inject into the presentational component. For example, we want the VisibleTodoList to inject a prop called onTodoClick into the TodoList component, and we want onTodoClick to dispatch a TOGGLE_TODO action:

stateを読むのに加えて、containerコンポーネントはactionsをdispatchすることができる。同様のやり方で、mapDispatchToProps()という関数を定義することもできる。それはdispatch()メソッドを受け取り,
presentationalなコンポーネントに挿入したいcallback props返す。例えば、onTodoClickと呼ばれるprop
をTodoListコンポーネントに渡すのにVisibleTodoListを必要とする。また、onTodoClickをTOGGLE_TODOアクションをdispatchするために必要とする