徒然なるままに

現在、海外にWebエンジニアになるべくカナダのカレッジに通い中。現地の生活やプログラミング、感じたことを気ままに書きます。

React-Reduxアプリケーション開発入門まとめ

概要

こんにちはtogashoです。

今回はフロントエンドエンジニアのためのReact・Reduxアプリケーション開発入門の基礎編で学んだReactとReduxの基本的なところを自分の忘備録も兼ねてをまとめてみました。

React

Facebook社が開発したライブラリー

  • DOMの変更箇所だけをレンダリングする
  • DOMの変更箇所がどこかを開発者が気にする必要がない

JSX

javascript XMLの略。

JSXの利点とは

jsでも表示できるが、JSXの方が直感的にコーディングでき可読性が高い。

文法

  • JSXが使われているときはreactをimportする必要がある。JSXを使わなければreactは必要ない。
  • {}の中では、jsが実行できる。
  • classはclassNameと定義する。
  • 属性名はキャメルケースで定義する。 onClickonChangeなど
  • returnで複数の要素を返す場合、divタグで囲む。Fragmentはdivタグで囲むのと同じ役割をするが、ブラウザ上では表示されない。

トランスパイル

JSXを実行可能なjsに変換すること。Babelが暗黙的にやっている。

Webpack

モジュールバンドラー。ソースコードを束ねて、一つのファイルにまとめて定義し、ブラウザで表示する。

コンポーネント

関数の定義によるものとクラス定義によるものがある。

// 関数定義
import React from 'react'

const Register = () => {
  return (
    <div>
      
    </div>
  )
}

export default Register
//クラス定義
import React, { Component } from 'react'

export default class Register extends Component {
  render() {
    return (
      <div>
        
      </div>
    )
  }
}

props

  • コンポーネントの属性の名前。{}で囲って値を渡す。親から子にデータを渡す。
  • immutable(変更不可能)な値
//ex)
import React from 'react'

const App = () => {
    const profiles = [
        {name: "Taro", age: 18},
        {name: "Sam", age: 21},
        {name: "Bob"},
    ]
return (
    <div>
        {
            // コンポーネントにpropsを渡す
            profiles.map((profile, index) => {
                return <User name={profile.name} age={profile.age} key={index} />
            })
        }
    </div>
)
}

// 親から渡されたpropsを引数として受け取る。
const User = (props) => {
  return (
    <div>Hi, I am {props.name}, and {props.age} years old!</div> 
  )
}

// デフォルトのpropsの設定
User.defaultProps = {
    age: 1
}

export default App

prop-types

  • propertiesに対する型のチェックをするためのパッケージ。
  • import Proptypes from 'prop-types'でimportする
  • isRequiredで必須にできる。
  • コンポーネントを設計する段階で、受け取るプロパティの型がぶれないように設計することが大事
//ex)
User.propTypes = {
    name: Proptypes.strng,
    age: Proptypes.number
}

State

  • コンポーネントの中で状態を保つこと。コンポーネント内部でしか使えない
  • mutable(変更可能)な値
  • this.stateでアクセスできる
  • this.setStateで状態を変える。setStateが実行されるとそのコールバックでrenderが再実行される
import React, { Component, Fragment } from 'react';

const App = () => (<Counter></Counter>);

class Counter extends Component {
  // constructorはcomponentの初期化時に呼ばれるコールバック
  constructor(props){
      super(props)
      this.state = { count: 0}
  }

  handlePlusButton(){
      this.setState({count: this.state.count +1 })
  }

  handleMinusButton(){
      this.setState({count: this.state.count - 1 })
  }

  render() {
    return (
        <Fragment>
            <div>count: {this.state.count}</div>
            <button onClick={this.handlePlusButton}>+1</button>
            <button onClick={this.handleMinusButton}>-1</button>
        </Fragment>
    )
  }
}

export default App;

Reduxの概要

コンポーネントの階層が大きくなった時に、容易に状態を共有する手段を提供する。

action

  • アプリケーションの中で何が起きたかを示すデータ。jsオブジェクトのこと。
  • typeというキー(ユニークでなけれならない)とタイプに対応する値を持つ。

    action creator

  • actionを定義して、それを返す関数のことをaction creatorと呼ぶ
  • typeで指定した値は、reducerでも使う。
  • viewを担当するコンポーネントがactionをimportして、あるイベントを掴んだ時に当該のaction creatorinvokeして適切な状態遷移を実行させるための仕組み。
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';

// action creator
export const increment = () => ({
    type: INCREMENT
})

export const decrement = () => ({
    type: DECREMENT
})

Reducer

  • actionが発生した時に、そのアクションに組み込まれているtypeに応じて状態をどのように変化させるのかを定義するもの
  • 状態は、コードの中ではstateという名称で扱う。
  • アプリケーションの事実上の状態を持つreducerを定義する。
// index.js
// アプリケーション内に存在する全てのreducerを総括する。全てのreducerを結合する。
//combineReducersがreducerを結合する
import { combineReducers} from 'redux';
import count from './count';

export default combineReducers({ count });
// counter.js
// actionをimportする
import { INCREMENT, DECREMENT} from '../actions/index';

//状態をの初期値を定義する
const initialState = { value: 0 }

// actionのtypeを受け取り、switch文で状態をどう変化させるのかを定義する。
export default (state = initialState, action) => {
    switch (action.type){
        case INCREMENT:
            return { value: state.value + 1}
        case DECREMENT:
            return { value: state.value - 1}
        default:
        return state
    }
}

Store

  • reducerをもとにstoreを作成する。そのstoreが全てのアプリケーション内で使えるようにする。createStore()で行う。
  • storeを全コンポーネントを参照できるようにするため、Providerreact-reduxから提供されている。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './components/App';
import './index.css';
import reducer from './reducers';

// アプリケーション内の全てのstateはこのstateに集約されている
const store = createStore(reducer)

// 既存のcomponentをProviderでラッピングする

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

connectでstateとactionsとの関連づけ

  • react-reduxが提供するconnect関数を使用して、stateやactionをコンポーネントに紐づける。viewのイベントで状態を遷移させ、遷移後の状態を再renderingする。
  • mapStateToPropsはstateの情報からこのコンポーネントで必要な物を取り出して、コンポーネント内のpropsとしてmappingする機能を持つ関数。引数には状態のtopレベルを表すstateを渡して、どういったオブジェクトをpropsに対応させるのかを関数の戻り値として定義する。
  • mapDispatchToPropsあるアクションが発生した時にreducerにtypeに応じた状態遷移を実行させる関数がdispatch。dispatch関数を引数において、このコンポーネントに必要となるdispatch関数を宣言する。
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
// action creatorを呼び出す。
import { increment, decrement } from '../actions';


class App extends Component {

  render() {
    const props = this.props;
    return (
        <Fragment>
            <div>value: { props.value }</div>
            <button onClick={props.increment}>+1</button>
            <button onClick={props.decrement}>-1</button>
        </Fragment>
    )
  }
}

// stateとcomponentを関連づける
const mapStateToProps = state => ({value: state.count.value});
const mapDispatchToProps = ({increment, decrement});

// 下記でも可
// const  mapDispatchToProps = dispatch => ({
//   increment: () => dispatch(increment()),
//   decrement: () => dispatch(decrement())
//})

// connectの引数にmapStateToPropsとmapDispatchToProps渡してAppに紐付ける。
export default connect(mapStateToProps, mapDispatchToProps)(App);

ご一読いただきありがとうございました。指摘事項等ございましたら、ご指摘いただけると幸いです。