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と定義する。
- 属性名はキャメルケースで定義する。
onClick
やonChange
など - 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 creatorをinvokeして適切な状態遷移を実行させるための仕組み。
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を全コンポーネントを参照できるようにするため、
Provider
がreact-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);
ご一読いただきありがとうございました。指摘事項等ございましたら、ご指摘いただけると幸いです。