Why does createStore work but configureStore doesn't? - javascript

I am creating a simple counter app using react and redux.
The following is the counterSlice.js file.
import { createSlice } from "#reduxjs/toolkit";
export const counterSlice = createSlice({
name: "counter",
initialState: { count: 0 },
reducers: {
changeValueBy(state, action) {
const value = action.payload;
state["count"] = state["count"] + value;
}
}
});
export const { changeValueBy } = counterSlice.actions;
export const selectCount = (state) => state.count;
export default counterSlice.reducer;
The following is the app/store.js file:
import { configureStore } from "#reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
export default configureStore({
reducer: {
counter: counterReducer
}
});
The following is the index.js file:
import App from "./App";
import store from "./app/store";
import { Provider } from "react-redux"
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
With this setup, the code doesn't work.
(Entire code is in this sandbox)
But with following setup, the store works.
The App.js file:
import { Counter } from "./features/counter/Counter";
import "./App.css";
import { Provider } from "react-redux";
import { createStore } from "redux";
import counterSlice from "./features/counter/counterSlice";
const store = createStore(counterSlice);
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Provider store={store}>
<Counter />
</Provider>
</header>
</div>
);
}
The entire code is in this sandbox.
I would like to use configureStore form the #reduxjs/toolkit package and not the outdated createStore from redux package.
Any idea how I can achieve this?

export default configureStore({
reducer: {
counter: counterReducer
}
});
is equivalent to
const store = createStore(combineReducers: {
counter: counterSlice
});
which means that the data from counterSlice will be found at state.counter.
Your old code does createStore(counterSlice), which means that the data from counterSlice will be found at state.
So, both work, but you will have to select the data from different places depending on what you do.
Your selector
export const selectCount = (state) => state.count;
would have to be
export const selectCount = (state) => state.counter.count;
instead.

Related

error - TypeError: Cannot read properties of undefined (reading 'getState') while using redux store in next.js

Just came across this issue error - TypeError: Cannot read properties of undefined (reading 'getState') with next.js and redux.
Here is my code below, I don't know the reason why I am facing this issue.
pages/app/store.js
import { configureStore } from "#reduxjs/toolkit";
import counterSlice from "../slices/counterSlice";
export const store = configureStore({
reducer: {
counter : counterSlice
}
});
pages/slices/counterSlicer.js
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
count : 0
};
export const counterSlice = createSlice({
name : "counter",
initialState,
reducers: {
increment : (state , action) => {
state.count += 1;
}
}
});
export const { increment } = counterSlice.actions;
export const getCount = (state) => state.counter.count;
export default counterSlice.reducer;
I never had dispatched any action yet, maybe dispatch later
pages/_app.js
import '../styles/globals.css'
import { Provider } from 'react-redux';
import { store } from '#reduxjs/toolkit';
function MyApp({ Component, pageProps }) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
)
}
export default MyApp;
and finally in pages/index.js
import styles from '../styles/Home.module.css'
import { useSelector } from 'react-redux'
import { getCount } from './slices/counterSlice'
export default function Home() {
const value = useSelector(getCount);
return (
<div className={styles.container}>
The value is {value}
</div>
)
}
Note: For more info let me tell you that I have tried the exact code in react app also, but the same code is working in react but not working in next.js
You can check the output of react in this image
You need to wrap props.
Please see this https://github.com/kirill-konshin/next-redux-wrapper/blob/master/packages/demo-redux-toolkit/pages/_app.tsx
Export wrapper from your store.js
import { createWrapper } from 'next-redux-wrapper';
...
export const wrapper = createWrapper(makeStore);
And your _app.js should be
import '../styles/globals.css'
import { Provider } from 'react-redux';
import { wrapper } from './store';
function MyApp({ Component, ...rest }) {
const { store, props } = wrapper.useWrappedStore(rest);
return (
<Provider store={store}>
<Component {...props} />
</Provider>
);
}
export default MyApp;

Cannot connect component to redux store

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.

Whenever I wrap my App with PersistGate it gives me "TypeError: users.map is not a function" in one component, otherwise it works fine

As the title says, I'm mapping through an array I have from an api in UserCardList component and it works fine but once I wrap App with PersistGate, it gives me "TypeError: users.map is not a function" and the error message from redux logger is "redux-persist: persist timed out for persist key "root". I really don't know what I'm doing wrong.
Any help would be highly appreciated.
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./redux/store";
import "./index.css";
import "tachyons";
import App from "./containers/App";
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<PersistGate persistor={persistor}>
<App />
</PersistGate>
</BrowserRouter>
</Provider>,
document.getElementById("root")
redux store
import { createStore, applyMiddleware } from "redux";
import { persistStore } from "redux-persist";
import thunkMiddleware from "redux-thunk";
import { createLogger } from "redux-logger";
import rootReducer from "../redux/root-reducer";
const logger = createLogger();
const middlewares = [logger, thunkMiddleware];
export const store = createStore(rootReducer, applyMiddleware(...middlewares));
export const persistor = persistStore(store);
export default { store, persistor };
root-reducer
import { combineReducers } from "redux";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import requestUsers from "./reducers";
const persistConfig = {
key: "root",
storage,
whitelist: ["users"],
};
const rootReducer = combineReducers({
users: requestUsers,
});
export default persistReducer(persistConfig, rootReducer);
UserCardList component
import React, { Fragment } from "react";
import UserCard from "./UserCard";
const UserCardList = ({ users }) => {
return (
<Fragment>
<h1 className="f1"> Users </h1>
{users.map((user) => {
return (
<UserCard
key={user.login.uuid}
image={user.picture.large}
firstName={user.name.first}
lastName={user.name.last}
email={user.email}
city={user.location.city}
country={user.location.country}
/>
);
})}
</Fragment>
);
};
export default UserCardList;
I have created a sample project here by taking the code from your question and everything looks fine for me. And the store is getting created and users is coming as expected.
There could be a possible error in the reducers which is not posted here. Please have a look at the sample project, hope it helps.
I see in redux store you have this:
export const store = createStore(rootReducer, applyMiddleware(...middlewares));
export const persistor = persistStore(store);
// you dont need line below, you exported store and persistore in lines above
export default { store, persistor };
In my case, adding timeout: null to the persist configuration solved my issue.
const persistConfig = {
key: 'keyOfStore',
storage: storage,
// There is an issue in the source code of redux-persist (default setTimeout does not cleaning)
timeout: null,
}
const appReducer = combineReducers({
...otherReducers,
keyOfStore: persistReducer(persistConfig, keyOfStoreRedfucer),
})
Got the solution from here

Could not find store using redux-form

Console is throwing the following error:
Could not find "store" in either the context or props of "Connect(Form(Form))". Either wrap the root component in a < Provider >, or explicitly pass "store" as a prop to "Connect(Form(Form))".
Done everything as said in redux-form tutorial, previously store was working with a mock reducer.
The line in which the error appears is where render() is executed -take a look at index.js file-.
configureStore.js
import { createStore } from 'redux';
import { devToolsEnhancer } from 'redux-devtools-extension';
import rootReducer from './rootReducer';
export default function configureStore(initialState = {}) {
const store = createStore(rootReducer, initialState, devToolsEnhancer());
return { store };
}
index.js
import React from 'react';
import { render } from 'react-dom';
import Root from './Root';
import './index.css';
import App from './whitesheet-components/App';
import registerServiceWorker from './registerServiceWorker';
import configureStore from './store/configureStore';
const { store } = configureStore();
const MOUNT_NODE = document.getElementById('root');
render(
<App>
<Root store={store} />
</App>,
MOUNT_NODE,
);
registerServiceWorker();
Root.js
import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
const Root = ({ store }) => (
<Provider store={store} />
);
Root.propTypes = {
store: PropTypes.object.isRequired,
};
export default Root;
rootReducer.js
// use combineReducers when they are more than one
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import mockReducer from './mockReducer';
const rootReducer = combineReducers({
mockReducer,
form,
});
export default rootReducer;
Form.js
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import PropTypes from 'prop-types';
import titleField from './titleField';
const Form = (props) => {
const {
handleSubmit, submitting,
} = props;
return (
<form onSubmit={handleSubmit}>
<Field component={titleField} />
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={submitting} onClick={() => console.log('boton para agregar input')}>
+
</button>
</div>
</form>
);
};
Form.propTypes = {
handleSubmit: PropTypes.any.isRequired,
submitting: PropTypes.any.isRequired,
};
// validate: nombreFuncion, // <--- validation function given to redux-form
export default reduxForm({
form: 'exerciseCreatorForm', // a unique identifier for this form
})(Form);
ExerciseCreator.js
import React from 'react';
import Form from './Form';
import './styles.css';
const ExerciseCreator = () => (
<div className="component-exercise-creator">
<Form />
</div>
);
export default ExerciseCreator;
Have the provider wraps the your App component, not the other way around. Like this:
// Root.js
// ...other codes...
const Root = ({ store, children }) => (
<Provider store={store}>{children}</Provider>
);
// ...other codes...
// index.js
// ...other codes...
render(
<Root store={store}>
<App />
</Root>,
MOUNT_NODE,
);
// ...other codes...

reducer switch statements not working

I've just started out with Redux and trying to implement a simple MERN App (for practice).
Everything in my code is working fine, but my reducer function is showing unexpected behaviour. When an action (which gets fetches data from express api) is called my reducer correctly goes to the particular switch case data logs successfully but then three times the default case is passed and data on my component which I log is showing null. Please Help.
Here's my code:-
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import articlesReducer from './store/reducers/articlesReducer';
import registerServiceWorker from './registerServiceWorker';
const rootReducer = combineReducers({
articles: articlesReducer
});
const store = createStore(rootReducer, applyMiddleware(thunk));
const app = (
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>
);
ReactDOM.render(app, document.getElementById('root'));
registerServiceWorker();
App.js
import React, {Component} from 'react';
import {Switch, Route} from 'react-router-dom';
import './App.css';
import Home from './components/Home/Home';
class App extends Component {
render() {
return (
<div>
<Switch>
<Route exact path="/" component={Home} />
</Switch>
</div>
);
}
}
export default App;
articles.js
export const getAllArticles = () => {
return dispatch => {
return (
fetch('http://localhost:5000/api/articles')
.then(res => res.json())
.then(data => {
dispatch({type: 'GET_ALL_ARTICLES', articles: data})
})
);
};
};
articlesReducer.js
const initialState = {
articles:null
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'GET_ALL_ARTICLES':
console.log('in reducer', action.type, action.articles[0]);
return {
...state,
articles: action.articles
};
default:
console.log('In default');
return state;
}
};
export default reducer;
myComponent
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getAllArticles } from '../../store/actions/articles.js';
class MainPage extends Component {
componentWillMount() {
this.props.initArticles();
console.log(this.props.articles);
}
render() {
return (
<div className="container">
<br />
<h1>Here comes the articles!!</h1>
</div>
);
}
}
const mapStateToProps = state => {
return {
articles: state.articles
};
};
const mapDispatchToProps = dispatch => {
return {
initArticles: () => dispatch(getAllArticles())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(MainPage);
The output in my console is somewhat like this:-
In default
In default
In default
{articles: null}
in reducer GET_ALL_ARTICLES {articles[0] Object}
I don't know what is the mistake. Thanks for help in advance.
I'm not sure whether this is actually the problem but you incorrectly access the articles. You have a root reducer with articles reducer:
const rootReducer = combineReducers({
articles: articlesReducer
});
which initial state is:
const initialState = {
articles:null
};
And in your mapDispatchToProps you "import" whole reducer state:
const mapStateToProps = state => {
return {
articles: state.articles
};
};
I think you wanted to access articles property
const mapStateToProps = state => {
return {
articles: state.articles.articles
};
};
Other than that everything seems to be fine. I would however as pointed in comment initialize articles as empty array [].
const initialState = {
articles: []
};

Categories

Resources