13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

reactを使ったアプリ開発の流れ

Last updated at Posted at 2016-12-19
1 / 17

reactを使ったアプリ開発

react.jsはviewの部分
データ管理にfluxフレームワークを導入が必要です

今回はreduxを利用したアプリ開発をベースに気をつける点などを説明します


componentとは

componentはUIを独立した再利用可能な部分に分割したものです

reactはcomponentを組み合わせてページを構成します

class ButtonComponent extends Component {
  render() {
    return (
      <button>
        ボタン
      </button>
    );
  }
}

props

componentでどのようなデータ描画するかは呼び出し元からpropsというデータをもらい描画します

  render() {
    return (
      <button
        onClick={this.props.onClick}
      >
        {this.props.buttonName}
      </button>
    );
  }

bind問題

ReactをES6で書いた場合に、イベントハンドラでthisがundefinedとなりメソッドが実行できないという問題

参考
http://qiita.com/konojunya/items/fc0cfa6a56821e709065

私のプロジェクトではstage-0でメソッド定義しています


onClick = (e) => {
  this.props.onClick(e.target.dataset.key)
}

render() {
  return (
    <button
      deta-key="test"
      onClick={this.props.onClick}
    >
      {this.props.buttonName
    </button>
  );
}

arrow関数で書いていたこともありますがrenderをシンプルにしたい
renderの度にfunctionが生成されるのも無駄だよね
ということから移行しました


propsのobjectの一部を書き換えたい

reactではprops/stateはimmutableなobjectとして扱います

勝手に上書きすると他の部分のrenderなどが勝手に変わる、意図したタイミングでレンダーされない
などのも問題が発生します

駄目な例

static propTypes= {
  item: React.PropTypes.shape({
    name: React.PropTypes.string,
    color: React.PropTypes.string,
  })
};

render() {
  this.props.item.color = '#000';
  return (
    <button
      style={{color: this.props.item.color}}
      deta-key="test"
    >
      {this.props.item.name}
    </button>
  );
}

immutableな変更の例

  const assigned = _.assign({}. this.props.item, {color: '#000'}})
  const updated = icepick.setIn(this.props.item, ['color'], '#000');


state

componentの状態に応じてrenderを変えたい場合、stateを使って管理できます

が、componentはstateを持たず、propsのデータを描画するviewに専念することで
componentとしての役割が明確になりテストもしやすくなります


redux

fluxフレームワークの一つ

Single source of truth
アプリの状態をもつStoreはただ1つ。

state is read-only
状態を変更するには必ずActionを発行しなければならない。

Changes are made with pure functions
Actionにより状態をどう変更させるかはReducerが行なう。

状態管理やレンダリングをきれいに分割できるのがメリット


presentation componenntとcontainer component

reduxでは描画に特化させたcomponentをpresentation componentとよび
presentation componenntとstoreを結びつけるためにcontainer componentという
概念を用いてデータの管理を区別します

以下 presentation component -> component
container component -> container
としています


container

componentにデータやコールバックを渡すcomponent

mapStateToPropsでstateから利用する値だけをとってpropsにセットします

onClickButton(key) {
  this.context.store.dispatch(action());
},

render() {
  return (
    <PageComponent>
      <ButtonComponent
        name: this.props.item.name,
        color: this.props.item.color,
        onClick={this.onClickButton}
      />
    </PageComponent>
  );
}

const mapStateToProps = (state: Object, ownProps: Object) => {
  return {
    name: state.name,
    color: state.color,
  };
};

export default connect(
  mapStateToProps
)(MainPageContainer);

action

actionはアプリケーションからの情報をstoreへ送る為のオブジェクト

actionはtypeを必ず持ちます

const SHOW_DIALOG = 'SHOW_DIALOG';

function showDialog() {
  return {
    type: SHOW_DIALOG,
    dialogProps: {
      show: true,
      title: 'New Dialog',
    },
  };
}

reducer

actionが起こった結果、どのようにstateが変化するかを対応するのがreducer

const initialState = {};
function reducer(state = initialState, action) {
  switch (action.type) {
  case SHOW_DIALOG:
    return _.assing({}, state, action.dialogProps);
  default:
    return state;
  }
}

reducerは分割してconbineReducerで結合したりするとreducerの管理がしやすくなります

export function createRootReducer(): Function {
  const reducers = {
    dialog: reduceDialog,
    button: reduceButton,
  };
  return reduceReducers(
    combineReducers(reducers),
    (state: Object = {}, action: Object) => {
      return {
        ...state,
      };
    }
  );
}



create-reducerを実装するとswitch文からも開放されて記述を減らせるのでおすすめ

export const reduceShowDialog = createReducer([], {
  [ActionTypes.SHOW_DIALOG](state, action) {
    return _.assing({}, state, action.dialogProps);
  }
})


reduxの非同期処理

  • redux-thunk
     - promiseを使った非同期処理

  • redux-sage
     - generatorを使った非同期処理

redux-thunkではactionCreaterが肥大化していけどpromiseでゴリゴリっとかけるので楽ではある
一方、redux-sagaはgeneratorが必要でpolyfil入れたり多くの人に学習コストがかかったりするのけど
action周りはすっきりかけるとは思います


style

inline styleかcssか

inline styleは物理的にstyleとhtmlが近いので修正は楽だけど、デザイナーが用意したcss等を
ちょっと修正したりする必要がでてきます

最近はpostCSSを使いlocal使って名前の重複を防ぎ、componentの中で使うclass名をシンプルなものにし、cssをそのまま使えるようにしています


デバッグ

  • react developer tools

chromeのdevtoolでcomponentがわかるようになります

  • redux-devtools

こちらもchromeの拡張。stateの変化や状態をみることができます


テスト

componentをシンプルにしておくとテストが楽になります

react-addons-test-utilsを使い
componentに任意のpropsを渡し、期待したnodeが生成されているかを判定するというテストができます

const props = {
  name: 'test',
  color: '#000'
};

const component = TestUtils.renderIntoDocument(
  <ButtonComponent
    {...props}
  />
);
const node = ReactDOM.findDOMNode(component);
assert(node.children.length === 1);

actionはredux-mock-storeを使ったりします


13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?