LoginSignup
44
50

More than 3 years have passed since last update.

React、Reduxとaxiosを使って郵便番号から住所を取得する

Last updated at Posted at 2019-06-21

React、Reduxの初心者向け記事です。
axiosを使ってAPIを叩き、その結果をReactで表示させたいと思います。

今回はこちらのサービスを使用させていただきました。
郵便番号-住所検索API

ミドルウェアの導入

Reduxで非同期処理をするためにはミドルウェアが必要となります。
ミドルウェアはredux-thunkredux-sagaが有名なようです。
redux-thunkは非同期処理をAction内で行い、redux-sagaはSagaという独立したプロセス内で行うという違いがありますが、今回は導入が簡単そうなredux-thunkを採用しました。

まずはredux-thunkをインストールします。

$ npm install redux-thunk

storeを作成している場所でredux-thunkを導入します。
createStore()にapplyMiddleware()を設定することでミドルウェアを導入することができます。

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux';
import './index.css';
import reducer from './reducers';
import Routes from './containers/Routes';

const store = createStore(
  reducer,
  applyMiddleware(thunk)
);

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

Actionを実装

次にActionを書いていきます。
最初にActionのタイプを作成し、ActionCreatorで非同期処理のリクエストを投げています。

Action.js
import axios from 'axios'
export const GET_ADDRESS_REQUEST = 'GET_ADDRESS_REQUEST'
export const GET_ADDRESS_SUCCESS = 'GET_ADDRESS_SUCCESS'
export const GET_ADDRESS_FAILURE = 'GET_ADDRESS_FAILURE'

export const getAddressRequest = () => {
  return {
    type: GET_ADDRESS_REQUEST
  }
}

export const getAddressSuccess = (data) => {
  return {
    type: GET_ADDRESS_SUCCESS,
    data
  }
}

export const getAddressFailure = (error) => {
  return {
    type: GET_ADDRESS_FAILURE,
    error
  }
}

export const getAddress = (zipcode) => {
  return async (dispatch) => {
    dispatch(getAddressRequest(zipcode))
    try {
      const res = await axios.get('https://api.zipaddress.net/?', { params: { zipcode: zipcode } });
      return dispatch(getAddressSuccess(res.data));
    }
    catch (err) {
      return dispatch(getAddressFailure(err));
    }
  }
}

Reducerを実装

先程作成したActionをつかってReducerを実装します。

Reducer.js
import {
  GET_ADDRESS_REQUEST, GET_ADDRESS_SUCCESS, GET_ADDRESS_FAILURE
} from '../actions/Action'

const initalState = {
  isFetching: false,
  address: []
}

const getAddress = (state = initalState, action) => {
  switch (action.type) {
    case GET_ADDRESS_REQUEST:
      return Object.assign({}, state, {
        isFetching: true,
        address: []
      });
    case GET_ADDRESS_SUCCESS:
      return Object.assign({}, state, {
        isFetching: false,
        address: action.data,
      });
    case GET_ADDRESS_FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      });
    default:
      return state
  }
}

export default getAddress

コンポーネントを編集

最後にviewの部分を実装します。

View.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getAddress } from '../actions/Action'

class View extends Component {

  constructor(props){
    super(props);
    this.state = {
      text: '',
      address: ''
    }

    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(e){
    if (e.target.value.length === 7) {
      this.props.getAddress(e.target.value)
    }
    this.setState({
      text: e.target.value
    })
  }

  componentWillReceiveProps(nextProps){
    if(nextProps.data){
      this.setState({
        address: nextProps.data.fullAddress
      })
    }
  }

  render() {
    return (
      <div>
        郵便番号から住所を表示します
        <br/>
        <input type='text' value={this.state.text} onChange={this.handleChange}></input>
        <p>入力した郵便番号:{this.state.text}</p>
        <p>住所: {this.state.address}</p>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  data: state.getAddress.address.data
});

function mapDispatchToProps(dispatch) {
  return {
    getAddress(zipcode){
      dispatch(getAddress(zipcode))
    }
  };
}

export default connect(mapStateToProps, mapDispatchToProps )(View);

スクリーンショット 2019-06-21 17.09.42.png

7桁の数字を入力した瞬間に住所を表示したかったので e.target.valueの値を直接getAddress にdispatchしています。
入力した瞬間はまだthis.props.dataがundefinedなためdispatchした直後はsetStateできません。
なのでcomponentWillReceivePropsを使用して、propsがなにかしら変化した直後にsetStateしています。

React.js のライフサイクルメソッド componentWillReceiveProps の廃止対応

componentWillReceivePropsはReactのv17以降廃止されるらしいので今後はUNSAFE_componentWillReceivePropsに書き換えるか、v16.3から新しく導入されたgetDerivedStateFromPropsに置き換える必要があるようです…

参考

React + ReduxでREST APIを叩いてリスト表示する方法
reduxで非同期処理をするいくつかの方法(redux-thunk、redux-saga)
React.js のライフサイクルメソッド componentWillReceiveProps の廃止対応

44
50
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
44
50