Redux Toolkit Tutorialを通してreduxを学ぶ　#3

## はじめに 
本記事は、「Redux Toolkit Tutorialを通してreduxを学ぶ　#2」の続きです。

・Reduxを使用した場合
・Reduxを使用しなかった場合

の両方のコードを比較し、最後にreduxを活用するメリットについて感じたことを記述します。


## 目次
- #3でやりたいこと
- Reduxを使用した場合の実装
- Redux使用有無を比較し感じたメリット

## やりたいこと
#2で実装したソースを、Reduxを使用した場合の実装に変更していく

## Reduxを使用した場合の実装
以降、#2で作成したサンプルプロジェクトを別名でコピーして、
コピー先プロジェクトに編集を加えていく。

```
$cp -R sample_ts_project_noRedux sample_ts_project_withRedux 
```


まず必要なパッケージをインストールする
```
$ npm install --sav-dev @reduxjs/toolkit react-redux
```


srcフォルダ配下にstore.tsxを作成する。
```
$ touch src/store.tsx
```

```tsx:src/store.tsx
import { PayloadAction, configureStore, createSlice } from "@reduxjs/toolkit";

interface UserStateValue {
    username: string;
}
interface UserState {
    value: UserStateValue;
}

const initialState = { value: {username: ""} } as UserState;
const userSlice = createSlice({
    name: "user",
    initialState,
    reducers: {
        login: (state: UserState, action: PayloadAction<UserStateValue> ) => {
            state.value = action.payload;
        },

        logout: (state: UserState) =>{
//  state must be immutable so this won't work
            // state = initialState;
// do this way
            state.value = initialState.value;
        },
    },
});

export const { login, logout } = userSlice.actions;
export const store = configureStore({
    reducer: {
        user: userSlice.reducer,
    },
});
```

App.txsからpropsで全ての子コンポーネントにステートを渡していた部分の記述が不要になる。
その代わりに、Providerタグで要素を囲む。

``` diff_tsx:components/App.tsx
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
import Home from "./Home";
import Login from "./Login";
import Contact from "./Contact";
- import { useState } from "react";
+ import { Provider } from "react-redux";
+ import { store } from "../store";

function App() {
-  const [newUsername, setNewUsername] = useState<string>("");

-  function updateUsername(name: string){
-    setNewUsername(name);
-  }

  return (
    <div className="App">
+      <Provider store={store}>
        <Router>
          <Link to="/">Home </Link>
          <Link to="/login">Login </Link>
          <Link to="/contact">Contact </Link>
          <Routes>
-            <Route path="/" element={<Home username={newUsername} />} />
+            <Route path="/" element={<Home />} />
-            <Route path="/login" element={<Login username={newUsername} onUpdate={updateUsername}/>} />
+            <Route path="/login" element={<Login />} />
-            <Route path="/contact" element={<Contact username={newUsername} />} />
+            <Route path="/contact" element={<Contact />} />
          </Routes>
        </Router>
+      </Provider>
    </div>
  );
}

export default App;

```

以下メソッドを用いることで、グローバルなステートを管理できる。
useDispatch：ステートを更新する
useSelector：ステートを取得する

```diff_tsx:components/Login.tsx
import { useState } from "react";
+ import { login, logout } from "../store";
+ import { useDispatch, useSelector } from "react-redux";
import Header from "./Header";
import Footer from "./Footer";

- interface Props{
-   username: string;
-   onUpdate: (name:string) => void;
- }

- function Loign(props: Props) {
+ function Loign() {
  const [inputUsername, setInputUsername] = useState<string>("");

+  const dispatch = useDispatch();
+  const username = useSelector((state: any) =>  state.user.value.username);
+  console.log("usename: " +username);
-  console.log("usename: " +props.username);


  function handleLogin(event:any) {
    event.preventDefault();
-   props.onUpdate(inputUsername);
+    dispatch(login({username: inputUsername}));
    setInputUsername("");
  }

  function handleLogout(event:any){
    event.preventDefault();
-   props.onUpdate("");
+    dispatch(logout());   
    setInputUsername("");

  }

  return (
    <div>
      <Header />
      <div className="login">
-        {props.username}
+        {username}
        <form className="login">
          <input
            name="loginV"
            placeholder="loginPH"
            value={inputUsername}
            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                console.log(e.target.value);
                setInputUsername(e.target.value);
            }}
          />
          <button onClick={handleLogin}> Submit login</button>
          <button onClick={handleLogout}> Logout</button>
        </form>
      </div>
      <Footer />
    </div>
  );
}

export default Loign;
```
```diff_tsx:components/Contact.tsx
import Header from "./Header";
import Footer from "./Footer";
+ import { useSelector } from "react-redux";

- interface Props{
-   username: string;
- }

- function Contact(props: Props) {
+ function Contact() {
+  const username = useSelector((state: any) => state.user.value.username);
  return (
    <div>
      <Header />
-      <div className="contact">Contact {props.username}</div>
+      <div className="contact">Contact {username}</div>
      <Footer />
    </div>
  );
}

export default Contact;
```

```diff_tsx:components/Home.tsx
import Header from "./Header";
import Footer from "./Footer";
+ import { useSelector } from "react-redux";

- interface Props{
-   username: string;
- }

- function Home(props:Props) {
+ function Home() {
    const username = useSelector((state: any) => state.user.value.username);
  return (
    <div>
      <Header/>
-      <div className="home"> Home route {props.username}</div>
+      <div className="home"> Home route {username}</div>
      <Footer/>
    </div>
  );
}

export default Home;
```

## Redux使用有無を比較し感じたメリット
- コンポーネント間のステートの受け渡しが容易になる
    - 親子関係ではない場合など
- useStateで管理するステートがコンポーネント内で完結する
    -　コンポーネント内にステートを追加した時などに他のコンポーネントへの副作用がない
- コードがシンプルになる
        - 親子関係だが、親と通い孫コンポーネントだけでステートを使いたい場合など
        　（バケツリレーみたいにpropsを渡さなくていい）

簡単なサンプルプロジェクトで試してみたが、なんとなく便利なものなんだなということは理解できた。
今後はAPI呼び出しなど、より発展的な使い方も勉強していこうと思う。


## 関連記事
- [Redux Toolkit Tutorialを通してreduxを学ぶ　#1](https://qiita.com/atok/items/3ff72c22e22d484f2c87)

- [Redux Toolkit Tutorialを通してreduxを学ぶ　#2](https://qiita.com/atok/items/439aa976ad675ca1a097)