'Change in redux store is not performing re-render wherever that state is being used

I am trying to get the token from the api's provided by spotify everything here works as expected except one. When my reducer updates my authentication state it doesn't perform the re-render in my component where ever auth token is used. It still showing undefined after updating the store but when i refresh the login url it shows changes that were previously made.

here is my login.jsx

import { generateAuthorizeUrl, extractUrlParams } from "../utils";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { scopes } from "../spotify";
import { signIn } from "../actions";

const Login = (props) => {
  const { refreshToken, loading, error } = useSelector((state) => state.auth);
  console.log(refreshToken, loading, error);

  const dispatch = useDispatch();

  const onClickHandler = function (e) {
    e.preventDefault();
    var a = document.createElement("a");
    a.href = generateAuthorizeUrl()(scopes);
    a.click();
  };

  useEffect(() => {
    if (window.location.search.includes("code=") && !refreshToken) {
      var { code, state } = extractUrlParams();
      dispatch(signIn(code, state));
    }
  }, [dispatch, refreshToken]);

  return (
    <div>
      {props.refreshToken}
      <button onClick={onClickHandler}>login with spotify</button>
    </div>
  );
};

export default Login;

here is my authAction to perform when spotify redirect me with code and state parameter in url

import axios from "axios";
import {
  USER_SIGNIN_FAILURE,
  USER_SIGNIN_REQUEST,
  USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { Base64, getItem } from "../utils";

// DISPATCH DATA FOR MAKING REQUEST STATE

const signInRequest = () => ({ type: USER_SIGNIN_REQUEST });

// DISPATCH DATA FOR SUCCESS AND FAILURE REQUEST

const signInResponse = (error = false, data) => ({
  type: error ? USER_SIGNIN_FAILURE : USER_SIGNIN_SUCCESS,
  payload: data,
});

// SIGN IN ACTION TO BE DISPATCHED TO REDUCER FOR LOGIN STUFF

export const signIn = (code, state) => async (dispatch, getState) => {
  dispatch(signInRequest());

  let _state = getItem(process.env.REACT_APP_STATE_KEY);

  //   CHECK IF STATE IS NULL OR PROVIDED STATE DOES NOT MATCHES STATE STORED IN LOCALSTORAGE

  if (!state || state !== _state) {
    // IF TRUE OUR AUTHORAIZATION FAILS
    dispatch(signInResponse(true, "state mismatched, Authorization failed"));
  } else {
    // ELSE MAKE REQUEST TO TOKEN URI FOR ACCEPTION TOKEN

    await axios({
      url: process.env.REACT_APP_TOKEN_URI,

      method: "POST",

      data: new URLSearchParams({
        code: code,
        redirect_uri: process.env.REACT_APP_REDIRECT_URI,
        grant_type: "authorization_code",
      }).toString(),

      headers: {
        Authorization: `Basic ${Base64.encode(
          `${process.env.REACT_APP_CLIENT_ID}:${process.env.REACT_APP_CLIENT_SECRET}`
        )}`,
        "Content-Type": "application/x-www-form-urlencoded",
      },
    })
      .then((res) => {
        dispatch(signInResponse(false, res.data));
      })
      .catch((error) => dispatch(signInResponse(true, error.message)));
  }
};

here is the authReducer

import {
  USER_SIGNIN_FAILURE,
  USER_SIGNIN_REQUEST,
  USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { setItem } from "../utils";

const AuthReducer = (state = { loading: false, error: "" }, action) => {
  switch (action.type) {
    case USER_SIGNIN_REQUEST:
      return { ...state, loading: true };

    case USER_SIGNIN_SUCCESS:
      let auth = {
        refreshToken: action.payload.refresh_token,
        accessToken: action.payload.access_token,
        expiresIn: new Date().getTime() + 3540 * 1000,
        tokenType: action.payload.token_type,
      };

      setItem(process.env.REACT_APP_TOKEN_KEY)(JSON.stringify(auth));

      return {
        ...state,
        loading: false,
        auth: auth,
        error: null,
      };

    case USER_SIGNIN_FAILURE:
      return { ...state, loading: false, error: action.payload, auth: {} };

    default:
      return state;
  }
};

export { AuthReducer };

here is store.js

import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import thunk from "redux-thunk";
import { AuthReducer } from "../reducers/AuthReducers";
import { getItem } from "../utils";

const initialState = {
  auth: getItem(process.env.REACT_APP_TOKEN_KEY)
    ? JSON.parse(getItem(process.env.REACT_APP_TOKEN_KEY))
    : {},
};

const rootReducer = combineReducers({
  auth: AuthReducer,
});

const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  rootReducer,
  initialState,
  composeEnhancer(applyMiddleware(thunk))
);

export default store;

Here is Login Component parent Container

import { BrowserRouter, Routes, Route } from "react-router-dom";
import styled from "styled-components";
import Privateroute from "./route/PrivateRoute";
import { Home, Login } from "./screens";

function App() {
  return (
    <BrowserRouter>
      <AppContainer>
        <Routes>
          <Route path="/auth/login" element={<Login />} />
          <Route
            path="/"
            element={
              <Privateroute>
                <Home />
              </Privateroute>
            }
          ></Route>
        </Routes>
      </AppContainer>
    </BrowserRouter>
  );
}

const AppContainer = styled.div``;

export default App;

and last here is my private route component

import React from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";

const Privateroute = (props) => {
  const token = useSelector((state) => state.auth.refreshToken);
  return token ? props.children : <Navigate to="/auth/login" />;
};

export default Privateroute;


Solution 1:[1]

You need to wrap your code with <Provider store={store}></Provider>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wraithy