Redux Toolkit でstateが初期化されてしまうエラーについて
Q&A
Closed
解決したいこと
現在、バックエンドにDjangoRESTFramework、フロントエンドにReactを用いたWebアプリケーションを実装しています。
Reactでユーザーの状態管理のため、Reduxを導入したのですが、ページ遷移によってstoreに保存したstateの値が初期化してしまいます。
具体的には、isLoggedInというstateを用意し、ログイン後にisLoggedInがtrueとなり、ログアウト後にisLoggedInがfalseとなるような実装をしました。
しかし、ログインした後にログアウトページに移動するとstateが初期化されてしまい、ログアウトする前にisLoggedInがfalseとなってしまいます。
このようなstore内のstateが、意図せず初期化されてしまうエラーを解決したいです。
発生している問題・エラー
ログイン前は、isLoggedInの値は初期値であるfalseになっています。
- ログイン後
ログイン処理後は、isLoggedInの値がtrueに変更されています。また、Actionを確認すると、以下のようにログインアクションが反映されていることを確認しました。
- ログアウトページに移動(まだログアウト処理はしていない)
ログアウトページに移り、まだログアウト処理をしていないのでisLoggedInがtrueを保持していて欲しいのですが、isLoggedInの値は初期値であるfalseに戻ってしまいます。ログアウトページに移った際にActionを確認すると、上記のように初期化されているような表示が出ます。
該当するソースコード
Redux関連は、src/storesに格納しています。
Redux関連
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
isLoggedIn: false
};
const slice = createSlice({
name: "user",
initialState,
reducers: {
isLoggedInOn: (state, action) => {
return {
...state,
isLoggedIn: true,
};
},
isLoggedInOff: (state, action) => {
return {
...state,
isLoggedIn: false,
};
},
}
});
// Reducerをエクスポートする
export default slice.reducer;
// Action Creatorsをエクスポートする
export const { isLoggedInOn, isLoggedInOff } = slice.actions;
import { combineReducers,compose } from "redux";
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./user";
const reducer = combineReducers({
user: userReducer
});
const store = configureStore({ reducer });
export default store;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from "react-redux";
import store from "./stores/";
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
ログイン、ログアウト部分
import React, { useState, useEffect, useRef } from 'react';
import { useCookies } from 'react-cookie';
import axios from 'axios';
import { useForm } from "react-hook-form";
import { useHistory } from 'react-router-dom';
import { apiURL } from './Default';
import { useDispatch, useSelector } from "react-redux";
import { isLoggedInOn } from "../stores/user";
const Login = (props) => {
const history = useHistory();
const dispatch = useDispatch();
const isLoggedIn = useSelector(state => state.user.isLoggedIn);
const [cookies, setCookie] = useCookies();
const { register, handleSubmit, watch, errors } = useForm();
const getJwt = async (data) =>{
console.log("ログイン"+isLoggedIn);
await axios.post(`${apiURL}auth/jwt/create/`,
{
email:data.email,
password:data.password,
},
)
.then(function (response) {
console.log(response.data.access)
dispatch(isLoggedInOn());
setCookie('accesstoken', response.data.access, { path: '/' }, { httpOnly: true });
setCookie('refreshtoken', response.data.refresh, { path: '/' }, { httpOnly: true });
history.push('/');
})
.catch(err => {
alert("EmailかPasswordが違います");
});
};
return (
<div className="top-wrapper">
<div class="login">
<h3>Login</h3>
</div>
<div class="login-block">
<form onSubmit={handleSubmit(getJwt)}>
<label for="email">Email:</label>
<input className='form-control' {...register('email')} />
<label for="password">PassWord:</label>
<input className='form-control' type="password" {...register('password', { required: true })} />
<input className='btn btn-secondary' type="submit" value="ログイン" />
</form>
</div>
</div>
);
}
export default Login;
import React, { useCookies } from 'react-cookie';
import { useHistory } from 'react-router-dom';
import Button from 'react-bootstrap/Button';
import { useDispatch, useSelector } from "react-redux";
import { isLoggedInOff } from "../stores/user";
const Logout = (props) => {
const history = useHistory();
const [cookies, setCookie, removeCookie] = useCookies();
const dispatch = useDispatch();
const RemoveJwt = () => {
removeCookie('accesstoken', { path: '/' }, { httpOnly: true });
removeCookie('refreshtoken', { path: '/' }, { httpOnly: true });
dispatch(isLoggedInOff());
history.push('/');
console.log("ログアウトしました")
console.log(cookies);
}
return (
<div>
<Button variant="success" onClick={RemoveJwt}>ログアウト</Button>
</div>
);
}
export default Logout;
ちなみに、ページルーティングはこのようになっています。
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Header from '../Header';
import Footer from '../Footer';
import Login from './Login';
import Top from './Top';
import Logout from './Logout';
//APIURL
export const apiURL = 'http://localhost:8000/api/v1/';
class Default extends React.Component {
render() {
return (
<div>
<Header />
<div className="main">
<Switch>
<Route exact path="/" component={Top} />
<Route exact path="/login" component={Login} />
<Route exact path="/logout" component={Logout} />
<Route render={() => <p>not found!.</p>} />
</Switch>
</div>
<Footer />
</div>
);
}
}
export default Default;
自分で試したこと
createSlice関数の書き方が悪いのかと考え、以下の記事を参考に色々書き換えたのですが、なかなか解決できませんでした。
- https://www.hypertextcandy.com/learn-react-redux-with-hooks-and-redux-starter-kit
また、本質問のコードには長さの関係で記述していないのですが、ログイン後に他のページに遷移してみたところ、stateの値が保持されるページもあれば初期化してしまうページも存在していました。
Reduxのstateが初期化される件について、調べてもなかなか出てこず、どなたか教えていただけないでしょうか?
どうぞよろしくお願いいたします。