LoginSignup
25
17

More than 3 years have passed since last update.

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

Posted at

クラスコンポーネントで作成していた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初心者ですが少しづつモダンな実装ができるように勉強していきます。

25
17
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
25
17