So I'm working on this Facebook clone and I see error
'Uncaught TypeError: user is null'.
Removing PersistGate component from my index.js file works, but I can't figure out how to solve the problem. And I need that component. Here's my code.
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import authReducer from "./state";
import { configureStore } from "#reduxjs/toolkit";
import { Provider } from "react-redux";
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from "redux-persist";
import storage from "redux-persist/lib/storage";
import { PersistGate } from "redux-persist/integration/react";
const persistConfig = { key: "root", storage, version: 1 };
const persistedReducer = persistReducer(persistConfig, authReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistor={persistStore(store)}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>
);
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
mode: "dark",
user: null,
token: null,
posts: [],
};
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setMode: (state) => {
state.mode = state.mode === "light" ? "dark" : "light";
},
setLogin: (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
setLogout: (state) => {
state.user = null;
state.token = null;
},
setFriends: (state, action) => {
if (state.user) {
state.user.friends = action.payload.friends;
} else {
console.error("user friends non-existent :(");
}
},
setPosts: (state, action) => {
state.posts = action.payload.posts;
},
setPost: (state, action) => {
const updatedPosts = state.posts.map((post) => {
if (post._id === action.payload.post._id) return action.payload.post;
return post;
});
state.posts = updatedPosts;
},
},
});
export const { setMode, setLogin, setLogout, setFriends, setPosts, setPost } = authSlice.actions;
export default authSlice.reducer;
I was trying to follow with redux-persist documentation, but couldn't solve the problem.
It looks like the issue may be that you are creating a new persistor anytime the PersistGate component rerenders for whatever reason. It's the only part of your setup where I see it deviate from the documentation.
I suggest creating the persistor once outside any React/JSX code.
const persistConfig = { key: "root", storage, version: 1 };
const persistedReducer = persistReducer(persistConfig, authReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
const persistor = persistStore(store); // <-- create outside JSX
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>
);
Related
The app works fine The only thing is that redux persist is not working as it should.Persist doest not persist anything,it does not give any errors in the console(in VSC or in Chrome) so I have zero information about where it is failing.Any ideas? thanks for your time and sorry for my bad english
This is the App.js
import FuseAuthorization from '#fuse/core/FuseAuthorization';
import FuseLayout from '#fuse/core/FuseLayout';
import FuseTheme from '#fuse/core/FuseTheme';
import history from '#history';
import { createGenerateClassName, jssPreset, StylesProvider } from '#material-ui/core/styles';
import { MuiPickersUtilsProvider } from '#material-ui/pickers';
import { create } from 'jss';
import jssExtend from 'jss-plugin-extend';
import rtl from 'jss-rtl';
import Provider from 'react-redux/es/components/Provider';
import { Router } from 'react-router-dom';
import { SnackbarProvider } from 'notistack';
import DateFnsUtils from '#date-io/date-fns';
import AppContext from './AppContext';
import { Auth } from './auth';
import routes from './fuse-configs/routesConfig';
import {store persistor} from './store';
import { PersistGate } from 'redux-persist/integration/react';
import { persistStore } from 'redux-persist';
const jss = create({
...jssPreset(),
plugins: [...jssPreset().plugins, jssExtend(), rtl()],
insertionPoint: document.getElementById('jss-insertion-point')
});
const generateClassName = createGenerateClassName({ disableGlobal: true });
const App = () => {
return (
<AppContext.Provider
value={{
routes
}}
>
<StylesProvider jss={jss} generateClassName={generateClassName}>
<Provider store={store}>
<PersistGate persistor={persistor}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Auth>
<Router history={history}>
<FuseAuthorization>
<FuseTheme>
<SnackbarProvider
maxSnack={5}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
classes={{
containerRoot: 'bottom-0 right-0 mb-52 md:mb-68 mr-8 lg:mr-80 z-99'
}}
>
<FuseLayout />
</SnackbarProvider>
</FuseTheme>
</FuseAuthorization>
</Router>
</Auth>
</MuiPickersUtilsProvider>
</PersistGate>
</Provider>
</StylesProvider>
</AppContext.Provider>
);
};
This is where the store is created:
import { configureStore } from '#reduxjs/toolkit';
import createReducer from './rootReducer';
import storage from 'redux-persist/lib/storage';
import { persistReducer } from 'redux-persist';
if (process.env.NODE_ENV === 'development' && module.hot) {
module.hot.accept('./rootReducer', () => {
const newRootReducer = require('./rootReducer').default;
store.replaceReducer(newRootReducer.createReducer());
});
}
const middlewares = [];
if (process.env.NODE_ENV === 'development') {
const { createLogger } = require(`redux-logger`);
const logger = createLogger({ collapsed: (getState, action, logEntry) => !logEntry.error });
middlewares.push(logger);
}
const persistConfig = {
key: 'root',
storage
};
const persistedReducer = persistReducer(persistConfig, createReducer());
export const store = configureStore({
reducer: persistedReducer,
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
immutableCheck: false,
serializableCheck: false
}).concat(middlewares),
devTools: process.env.NODE_ENV === 'development'
});
store.asyncReducers = {};
export const injectReducer = (key, reducer) => {
if (store.asyncReducers[key]) {
return false;
}
store.asyncReducers[key] = reducer;
store.replaceReducer(createReducer(store.asyncReducers));
return store;
};
export const persistor = persistStore(store);
This is the createReducer():
import { combineReducers } from '#reduxjs/toolkit';
import auth from 'app/auth/store';
import fuse from './fuse';
import i18n from './i18nSlice';
const createReducer = asyncReducers => (state, action) => {
const combinedReducer = combineReducers({
auth,
fuse,
i18n,
...asyncReducers
});
/*
Reset the redux store when user logged out
*/
if (action.type === 'auth/user/userLoggedOut') {
state = undefined;
}
return combinedReducer(state, action);
};
export default createReducer;
Hi Im trying to build a todo app and trying to add todos in todo list but I get this error:
TypeError: Cannot read property 'map' of undefined
here is the error code:
4 | function TodoList() {
5 | const list = useSelector((state) => state.todoList.text);
6 | return (
> 7 | <div>
8 | {list.map((todo)=>{
9 | <li>todo</li>
10 | })}
here is the TodoList.js:
import React from "react";
import { useSelector } from "react-redux";
const TodoList = () => {
const list = useSelector((state) => state.todoList.text);
return (
<div>
{list.map((todo)=>{
<li>todo</li>
})}
</div>
);
}
export default TodoList;
here is the index.js:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { TodoReducer,TodoListReducer } from "./redux/reducers";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
const rootReducer = combineReducers({
todoList: TodoListReducer,
todos: TodoReducer
});
const middleware = [thunk];
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(...middleware))
);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>{" "}
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();
here is the reducers.js:
import { SET_VALUE } from "./actions";
import {ADD_TODO} from "./actions"
let initial_state = [{
text:""
}]
export const TodoReducer = (state = initial_state, action) => {
switch (action.type) {
case ADD_TODO:
return [{
text: action.text,
}]
default:
return state;
}
}
export const TodoListReducer = (state = initial_state, action) => {
switch (action.type) {
case SET_VALUE:
return {
...state,
text: action.text
}
default:
return state;
}
}
Actually I'm a new coder so I might have a lot of mistakes :). Thank you for your attention.
state.todoList is an array of object. So just update like this:
const list = useSelector((state) => state.todoList);
The initial state dont have the property 'todoList' so that state.todoList is undefined.
Set a default value for it like let initial_state = {todoList:[{text:""}]}
In my profile page I have 3 cards, which means 3 react-components.
I am new to React.js and recently set up redux in my application. So the problem is two of them (cards) successfully connected to redux store, but third card can't for unknown reasons, can you help me please?
Redux store just returns undefined only for Card3.js
Hero.js (Profile)
import React, { useState, useEffect } from "react"
import FadeIn from 'react-fade-in';
import { Redirect } from 'react-router-dom'
import { Container, Row } from 'react-bootstrap'
import { getUserProfile } from "../../services/user.service";
import { connect } from "react-redux";
import './profile.css'
import LCard1 from "./cards/card1/LCard1"
import Card1 from "./cards/card1/Card1"
import Card2 from "./cards/card2/Card2"
import Card3 from "./cards/card3/Card3"
const Hero = (props) => {
const [userInfo, setUserInfo] = useState({username: ''})
const [isLoading, setIsLoading] = useState(true)
const getUser = async () => {
console.log()
await getUserProfile(props.uid)
.then(res => {
setUserInfo(res)
setIsLoading(false)
})
}
useEffect(() => {
if (userInfo)
getUser()
}, [])
return (
<>
<FadeIn transitionDuration={1000}>
{props.authenticated ? (
<section className="profile-cards">
<Container fluid >
<Row>
{isLoading ? (
<LCard1 />
) : (
<Card1 user={userInfo} />
)}
<Card3 />
</Row>
<Row>
<Card2 />
</Row>
</Container>
</section>
) : (
<Redirect to="/signin" />
)}
</FadeIn>
</>
)
}
const mapStateToProps = (state) => {
return {
uid: state.authReducer.uid,
authenticated: state.authReducer.authenticated
}
}
const mapDispatchToProps = (dispatch) => {
return {
logout: () => {
dispatch({
type: 'SIGNOUT_SUCCESS'
})
}
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Hero)
Card3.js
import React from 'react'
import { connect } from "react-redux";
import CreateAdvertisement from './content/create.advert/CreateAdvertisement'
import MyMessages from './content/my.messages/MyMessages';
import MySettings from './content/my.settings/MySettings';
import MyVerfifcation from './content/my.verif/MyVerfifcation';
import './card3.css'
const Card3 = (props) => {
return (
<div>
<p>Test: {props.username}</p>
<section className="card3">
<div className="card3-box">
<div>
<MySettings />
</div>
</div>
</section>
</div>
)
}
const mapStateToProps = (state) => {
return {
key: state.authReducer.username
}
}
export default connect(
mapStateToProps
)(Card3)
store.js
import { configureStore } from '#reduxjs/toolkit'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import thunk from 'redux-thunk'
import reducers from './reducers/root.reducer'
const persistConfig = {
key: 'root',
storage: storage,
blacklist: ['sidebarReducer']
}
const persistedReducer = persistReducer(persistConfig, reducers)
const store = configureStore({
reducer: persistedReducer,
devTools: process.env.NODE_ENV !== 'production',
middleware: [thunk]
})
export default store
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore } from 'redux-persist'
import store from './store/store'
let persistor = persistStore(store)
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
);
import React, { Component } from 'react';
import { View, Text,ScrollView } from 'react-native';
import { Provider } from 'react-redux'
import store from './src/Redux/Store'
import MainNavigation from './src/components/Navigation/Navigation';
class App extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<Provider store={store}>
<MainNavigation/>
</Provider>
);
}
}
export default App;
First your all screens should under a navigation then
follow this code This will work for you Thanks.
I am using Next.js(SSr) with redux. I have successfully implemented react-persist with the nextjs.
the user state is updated after login and value is update in the redux store and simultaneously in the localStorage's store but whenever I delete the localStorage item which contains the store and refresh the page,the localStorage is filled by the first version of the store i.e the initial store.
I though there might be problem in re hydration but i think PersistGate is handling it efficiently.
Can someone point out what went wrong in implementation ?
thanks in advance :)
_app.js
import withRedux from 'next-redux-wrapper'
import { withRouter } from 'next/router'
import { Provider } from 'react-redux'
import App from 'next/app'
import Layout from 'components/Layout'
import createStore from 'store/createStore'
import { persistStore } from 'redux-persist'
import { PersistGate } from 'redux-persist/integration/react'
class MyApp extends App {
static async getInitialProps ({ Component, ctx }) {
return {
pageProps: Component.getInitialProps
? await Component.getInitialProps(ctx)
: {}
}
}
constructor(props) {
super(props)
this.persistor = persistStore(props.store)
}
render () {
const { Component, pageProps, store, router } = this.props
return (
<>
<Provider store={store}>
<PersistGate
loading={<Component {...pageProps} />}
persistor={this.persistor}
>
<Layout>
<Component router={router} {...pageProps} />
</Layout>
</PersistGate>
</Provider>
</>
)
}
}
export default withRedux(createStore, {debug: true})(
withRouter(MyApp)
)
createStore.js
import Immutable from 'immutable'
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import { composeWithDevTools } from 'redux-devtools-extension'
import { createStore, applyMiddleware } from 'redux'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import config from 'config'
import rootReducer from '../reducers'
const persistConfig = {
key: 'primary',
storage,
whitelist: ['user'],
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
function createMiddlewares ({ isServer }) {
const middlewares = [
thunkMiddleware
]
if (config.env === 'development' && typeof window !== 'undefined') {
middlewares.push(createLogger({
level: 'info',
collapsed: true,
stateTransformer: (state) => {
const newState = {}
for (const i of Object.keys(state)) {
if (Immutable.Iterable.isIterable(state[i])) {
newState[i] = state[i].toJS()
} else {
newState[i] = state[i]
}
}
return newState
}
}))
}
return middlewares
}
function immutableChildren (obj) {
const state = {}
Object.keys(obj).forEach((key) => {
state[key] = Immutable.fromJS(obj[key])
})
return state
}
export default (initialState = {}, context) => {
const { isServer } = context
const middlewares = createMiddlewares({ isServer })
const state = immutableChildren(initialState)
return createStore(
persistedReducer,
state,
composeWithDevTools(applyMiddleware(...middlewares))
)
}
Img: initial store loaded instead of updated store after localStorage item is removed and page is refreshed
If you are using the redux-persist you no need to bind the PersistGate with provider...you can remove it and try again hope it will solve your issue...This is because you are already wrapping the component with withRedux hook.
return (
<PersistGate
loading={<Component {...pageProps} />}
persistor={this.persistor}
>
<Layout>
<Component router={router} {...pageProps} />
</Layout>
</PersistGate>
)
This will be enough
I am trying to persist my immutable states in localStorage. Below is my reducer index.js
import { combineReducers } from 'redux';
import posts from './PostReducer';
import polls from './PollReducer';
import categories from './CategoryReducer';
import activeThreads from './ActiveThreadReducer';
export default combineReducers({
posts,
polls,
categories,
activeThreads
})
In my persistStore.js, i have something like below.
import immutableTransform from 'redux-persist-transform-immutable'
import { persistStore, autoRehydrate } from 'redux-persist-immutable';
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const config = {
key: 'root',
storage,
};
const loggerMiddleware = createLogger();
const finalCreateStore =
composeWithDevTools(
applyMiddleware(
thunkMiddleware,
loggerMiddleware,
),
autoRehydrate()
);
const reducer = persistReducer(config, reducers)
export const store = createStore(reducer, undefined, finalCreateStore);
export const persistor = persistStore(store, { transforms: [immutableTransform({})] }, () => {
console.log('rehydration complete', store.getState());
return store;
});
and in my main APP,
return (
<Provider store={store}>
<PersistGate
loading={<Loading />}
onBeforeLift={this.onBeforeLift}
persistor={persistor}>
<Router history={browserHistory}
createElement={this.createElementWithActions}>
<Route path="/" component={Main}>
...
</Router>
</PersistGate>
</Provider>
);
My app is returning the error below.
Uncaught TypeError: persistor.getState is not a function
at PersistGate._this.handlePersistorState (react.js:41)
at PersistGate.componentDidMount (react.js:55)
at ReactCompositeComponent.js:262
at measureLifeCyclePerf (ReactCompositeComponent.js:73)
at ReactCompositeComponent.js:261
at CallbackQueue.notifyAll (CallbackQueue.js:74)
at ReactReconcileTransaction.close (ReactReconcileTransaction.js:78)
at ReactReconcileTransaction.closeAll (Transaction.js:207)
at ReactReconcileTransaction.perform (Transaction.js:154)
at batchedMountComponentIntoNode (ReactMount.js:124)
I read the documentation on redux-persist here and Here. Please what am i doing wrong and what does the error implies ?Anyhelp would be appreciated