Kartik sharma
Kartik sharma

Reputation: 45

Redux Store set to null when refresh the page

Index.js

Redux Store

This is Redux store file where I am setting the details of the authenticated user by dispatching an action.

import { createStore } from "redux";
function reducerFunction(state = {authenticatedUser: null}, action){                      
    console.log("It is working");
    if(action.type === "USER_LOGIN"){
        console.log(action.payload);
        return {authenticatedUser: action.payload}
    }
    return {authenticatedUser: null}
}
export const store = createStore(reducerFunction);

Login.js

This is My Login Page. When user successfully logged in then I am dispatching an action to update the state in redux store. In this I am dispatching an action to set the authenticated user details in redux store.

import { useState } from "react";
import { Link, useHistory } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
const Login = () => {
  const dispatch = useDispatch();
  const history = useHistory();
  const [email, setemail] = useState("");
  const [password, setpassword] = useState("");

  const emailChangeHandler = (e) => {
    setemail(e.target.value);
  };

  const passwordChangeHandler = (e) => {
    setpassword(e.target.value);
  };

  const submitHandler = async (e) => {
    e.preventDefault();
    const userData = {
      email,
      password,
    };
    try {
      const response = await fetch("/login", {
        method: "POST",
        body: JSON.stringify(userData),
        headers: {
          "Content-Type": "application/json",
        },
      });
      const data = await response.json();
      console.log(data);
      localStorage.setItem("jwt", data.token);
      localStorage.setItem("user",
        JSON.stringify({
          name: data.user.name,
          email: data.user.email,
          _id: data.user._id,
        })
      );
      dispatch({ type: "USER_LOGIN", payload: data.user });        //Here I am dispatching an action to set the authenticated user details in redux store.
      history.push("/");
    } catch (e) {
      console.log(e);
    }
    setemail("");
    setpassword("");
  };
  return (
    <div className="mycard">
      <div className="card auth-card input-field">
        <h2>Instagram</h2>
        <form onSubmit={submitHandler}>
          <input type="text" placeholder="email" onChange={emailChangeHandler} value={email} />
          <input type="text" placeholder="password" onChange={passwordChangeHandler} value={password} />
          <button className="btn waves-effect waves-light" type="submit" name="action" > Submit </button>
        </form>
        <p>
          <Link to="/signup">Don't have an account?</Link>
        </p>
      </div>
    </div>
  );
};
export default Login;

Profile.js

This is authenticated user profile page. Here I am displaying the name of authenticated user by fetching data from redux store. authenticatedUser.name

import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import classes from "./Profile.module.css";
const Profile = () => {
    const [images, setImages] = useState([]);
    const [image, setImage] = useState("");
    const [url, setUrl] = useState("");
    const dispatch = useDispatch();
    const authenticatedUser = useSelector(state => state.authenticatedUser);    //Here I am fetching authenticated user.


    useEffect(async() => {
        const response = await fetch("/myPost", {
            method: "GET",
            headers: {
                "Authorization": "Bearer " + localStorage.getItem("jwt"),
                "Content-Type": "application/json"
            }
        })
        const data = await response.json();
        console.log(data);
        setImages(data);
    }, [])

    return (
        <div>
            <div>
                <div>
                    <img className={classes.profile_image} src="https://images.unsplash.com/photo-1534972195531-d756b9bfa9f2?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80"/>
                </div>
                <div >
                    <h1>{authenticatedUser.name}</h1>
                    <div>
                        <h4>80 posts</h4>
                        <h4>80 followers</h4>
                        <h4>80 following</h4>
                    </div>
                </div>
            </div>

            <div className={classes.gallery}>
                {images.map(image => {
                    return <img src={image.image}/>
                })}
            </div>
        </div>
    );
}
export default Profile;

From here's the main problem starts. When I refresh the page it is showing error Cannot read property 'name' of null. When I search about this error then I get to know that the redux store set to default value when the page refresh. And then i found that redux-persist will help us to store data to local storage. But know I don't understand how to apply this redux-persist npm package. Please help me.? And Please tell me all these assumptions are right or not.?

Upvotes: 2

Views: 4998

Answers (2)

AR Saiyad
AR Saiyad

Reputation: 9

If your Redux store is being set to null when you refresh the page, it indicates that the state is not persisted between page reloads. Redux itself does not handle state persistence by default.

To persist the Redux state across page refreshes, you can use additional libraries or techniques such as browser local storage or session storage. Here's an example of how you can implement state persistence using local storage:

Install the redux-persist library:

npm install redux-persist

Set up the Redux store with Redux Persist in your application:

import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // Defaults to local storage

import rootReducer from './reducers'; // Your root reducer

const persistConfig = {
  key: 'root',
  storage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = createStore(persistedReducer);
export const persistor = persistStore(store);

In this code, persistConfig specifies the key and storage method to use for persisting the Redux state. The persistReducer function wraps your root reducer with the persistence configuration. The store and persistor are exported to be used in your application.

Wrap your application component with PersistGate from redux-persist:

import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';

import { store, persistor } from './store';

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        {/* Your application component hierarchy */}
      </PersistGate>
    </Provider>
  );
};

export default App;

Make sure to review the Redux Persist documentation for more advanced configuration options and customization based on your specific needs.

Upvotes: 1

Shailendra Kanherkar
Shailendra Kanherkar

Reputation: 99

Redux data will be set to initial state that is 100% true, You can make use of any browser storage as per requirement(localStorage/sessionStorage/cookies)..

I will share you example for storing full redux store and retrieving when browser is refresh(ideally not recommended), You can save the only that data which is required on browser refresh.

This method will be called on evert store update

store.subscribe(()=>{
  // save a copy to localStorage
  localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})

When page is refresh check weather we have anything in localStorage

const persistedState = localStorage.getItem('reduxState') 
                       ? JSON.parse(localStorage.getItem('reduxState'))
                       : {}

If we have we can pass it at the time of creating store

const store = createStore(
      reducer, 
      persistedState,
     /* any middleware... */
)

Important Note: Ideally not recommended to store full store data in localStorage...

Upvotes: 2

Related Questions