Help us understand the problem. What is going on with this article?

React Redux + React RouterにHooksを導入する

クラスコンポーネントで作成していたReactのプロジェクトを、React Hooksを使用した関数コンポーネントにリファクタリングする際に、React ReduxとReact RouterもHooksに対応させました。
その時に対応の仕方を簡単にですがまとめました。
React Reduxはv7.1から、React Routerはv5.1からHooksに対応しています。

環境

  • React : 16.12.0
  • React Redux : 7.2.0
  • React Router : 5.1.2

Redux Hooks

React ReduxがHooksに対応したことにより、各コンポーネントにおいて簡単にdispatchstateを利用できるようになりました。今回は以下の3点について説明します。

  • ActionをStoreにDispatchするmapDispatchToProps → useDispatch()
  • StoreからStateを取得するmapStateToProps → useSelector()
  • ReactコンポーネントとReduxのStoreを紐付けるconnect → いらない

mapDispatchToPropsuseDispatch()に、mapStateToPropsuseSelector()を使うことで、Hooksに対応できます。これで各コンポーネントで簡単にdispatchとstateを利用することができます。またconnect()を使用する必要がなくなります。

mapDispatchToProps

まずはmapDispatchToPropsでActionをStoreにDispatchしていたところを、useDispatch()で置き換えます。
基本的な使い方は以下のようになります。Actionに登録されている関数をgateDataとしておきます。

  • mapDispatchToprops
class App extends Component{
    componentDidMount(){
        this.props.gateData();
    }

    render(){
        // JSX
    }
}

const mapDispatchToProps = (dispatch) => {
    return{
        gateData: () => dispatch(gateData())
    }
}
  • useDispatch()
const App = () => {
    // mapDispatchToPropsの部分
    const dispatch = useDispatch();

    useEffect(()=>{
        // this.props.gateData()の部分
        dispatch(gateData());
    })

    return(
        // JSX
    )
}

完全に関数コンポーネント内にReduxの実装をまとめることができます。さらに直感的にReduxの機能を使用することができます。

mapStateToProps

次はmapStateToPropsでStoreからStateを取得していたところを、useSelector()を使用して、Hooksに対応します。
基本的な使い方は以下のようになります。Reducerに登録されているstateをdataとしておきます。

  • mapStateToProps
class App extends Component{
    render(){
        const { data } = this.props;
        return(
            // JSX
        )
    }
}
const mapStateToProps = (state) => {
    return{
        data: state.data
    }
}
  • useSelector
const App = () => {
    // mapStateToProps & this.propsの部分
    const data = useSelector(state => state.data);

    return(
        // JSX
    )
}

一目でわかりますが、useSelectorを使用するだけでStoreからStateを取得することができます。

独自Hooksと組み合わせる

Hooks APIとRedux Hooksを組み合わせて、Actionを実行してReducerからStateを取得する独自Hooksを作成します。
例として以下のようなクラスコンポーネントがあったとします。

class App extends Component{

    componentDidMount(){
        this.props.getData();
    }

    render(){
        const { data } = this.props;
        return(
            // JSX
        )
    }
}

const mapDispatchToProps = (dispatch) => {
    return{
        getData: () => dispatch(getData())
    }
}

const mapStateToProps = (state) => {
    return{
        data: state.data
    }
}

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

上記のクラスコンポーネントを独自Hooksを利用して、関数コンポーネントで実装します。

const useGetData = () => {
    const dispatch = useDispatch();
    const data = useSelector(state => state.data);

    useEffect(() => {
        dispatch(getData());
    })

    return data;
}


const App = () => {

    const data = useGetData();

    return(
        // JSX
    )
}

export default App;

Hooks APIとRedux Hooksを利用してActionを実行してStateを返す独自HooksのuseGetDataと、データを表示するコンポーネントAppに分離することができます。Reduxを利用してデータを取得するロジック部分をコンポーネントから切り離すことができるので、ロジック部分は他のコンポーネントでも使いまわせます。
コンポーネントごとに、connectmapDispatchToPropsmapStateToPropsを記述する煩わしさからも解放されます。コードもすっきりしますね。

以上がRedux Hooksの使い方でした。

React Router Hooks

React RouterがHooksに対応したことにより、これまでコンポーネントのpropsから取得していたhistoryparamsを関数を用いて、どこからでも取得することができます。
つまりコンポーネント以外の関数からも使用できるようになります。

以下の3つを説明します。

  • useHistory() : ページ遷移で使用するhistoryを取得する
  • useLocation() : 現在のURLやpathやクエリパラメータを取得する
  • useParams() : URLからパスパラメータを取得する

useHistory

useHistory()を使用することで、ページ遷移で使用するhistoryを取得することができます。
Hooks未対応の場合、コンポーネントのpropsからhistoryを取得します。そのため、クラス内でしか取得できませんでした。
useHistroy()を使うことで、コンポーネント以外でもhistoryを取得することができます。

const App = () => {
    const history = useHistory();

    const handleOnclick = (e) => {
        e.preventDefault();
        // 画面遷移
        history.push('/');
        // props.history.push('/');
    }
    return(
        <Link onClick={handleOnclick}>
            Link
        </Link>
    )
}

historyを取得できれば、history.push('/')history.goBack()を実行することができます。

useLocation

useLocation()を使用することで、現在のページのURLやクエリパラメータを取得することができます。
Hooks未対応の場合、コンポーネントのpropsからlocationを取得し、pathからURLをsearchからクエリパラメータを取得ます。そのため、クラス内でしか取得できませんでした。
useLocation()を使うことで、コンポーネント以外でもlocationを取得することができます。

?id=1&name=sampleというクエリパラメータを設定したとします。

const App = () =>{
    // const location = props.location;
    const location = useLocation();
    // URLを取得
    const path = location.path;
    // クエリパスを取得
    const query = location.serach;
    return(
        <>
            <p>{path}</p>
            <p>{query}</p>
        </>
    )
}

useParams

React Routerでは、<Route exact paht='/url/:id' component={}></Route>のように、pathに:~とすることで、URLからパスパラメータを取得することができます。
クラスコンポーネントでは、コンポーネントのpropsから取得します。
useParams()を使うことで、コンポーネント以外でもparamsを取得することができます。

const App = () => {
    // URLパラメータを取得
    const {id} = useParams();
    // const id = this.props.match.params.id;
    return(
        <>
            {id}
        </>
    )
}

React RouterのRouteの:~の~の変数を合わせることで、パスパラメータを取得することができます。

簡単ですが、React Routerで使用した、useHistory, useLocation, useParamsの使い方でした。総じてReact RoterがHooksに対応したことで、関数のどこからでも使用することができるようになったことがメリットかなと思います。

まとめ

簡単にですがReduxとReact RouterのHooks対応をまとめました。
ReduxとReact Router共に、それぞれの機能を関数を呼び出すことで利用できるので、独自Hooksとの親和性が高いのかなと感じました。
全体的にも実装の仕方がシンプルで使いやすく見やすくなってます。
まだまだReact初心者ですが少しづつモダンな実装ができるように勉強していきます。

t_okkan
rakus
「IT技術で中小企業を強くします!」というミッションを掲げ、中小企業の業務効率化に貢献する複数のクラウドサービスを提供しているIT企業です。「楽楽精算」「メールディーラー」など、国内トップシェアを誇る複数のサービスを開発し、累計導入社数は5万社を超えています。次の時代の"楽"を創るための、まだ見ぬサービスや機能を生み出す取り組みは、今日も続いています。
https://www.rakus.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした