can anybody please tell me why is my redux app not working? I have been going step by step from tutorial from youtube but my state isn't event shown in redux dev tools. All I have there is 'states are equal'.
counter.js file (reducer)
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
}
export default counterReducer;
index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
//reducer
import counterReducer from './Reducers/counter';
//store
import {createStore} from 'redux';
//provider
import { Provider } from 'react-redux';
const store = createStore(
counterReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
What Am I doing wrong?
try this code below in your index.js file.
import { createStore, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
counterReducer,
composeEnhancers()
);
and if you are using any middleware like redux-thunk, then do as following,
import { createStore, applyMiddleware, compose } from 'redux';
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunk))
);
If you want to update anything inside redux store then you have to dispatch an action mandatorily. Create an action, dispatch that action from your component. Then you will see everything working.
The above rated solution is accurate, but we have some cases when we don't want the end users to see our state using React DevTools. For example, in a production environment, we don't want this to happen. To implement this functionality use this chunk of code.
import { createStore, compose } from 'redux';
// if env is not equal to 'production', show state in Redux DevTools
const composeEnhancers = (process.env.REACT_APP_NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
const store = createStore(counterReducer,composeEnhancers());
// rest of the code goes here...
My solution was to change from "Autoselect instances" in the right upper corner to my own instance. The state was 'hidden' and that's why I couldn't see it despite configured everything correctly.
Related
I'm currently trying to use React + Typescript + Redux and I'm running into an issue. I'm trying to test the Redux Store setup via chrome devTools. I know I butchered the code (very new to Typescript) and I'm getting this error 'Uncaught TypeError: Cannot read properties of undefined (reading 'dispatch')' every time I test it. I tried declaring a global window state, installed redux-dev-tools, but still very lost.
This is what my store/index.tsx file look like:
import {
legacy_createStore as createStore,
combineReducers,
applyMiddleware,
compose,
StoreEnhancer,
} from "redux";
import { devToolsEnhancer } from "redux-devtools-extension";
import thunk from "redux-thunk";
const rootReducer = combineReducers({});
let enhancer;
if (process.env.NODE_ENV === "production") {
enhancer = applyMiddleware(thunk);
} else {
const logger = require("redux-logger").default;
const composeEnhancers =
(window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
enhancer = composeEnhancers(applyMiddleware(thunk, logger));
}
const configureStore = () => {
return createStore(rootReducer, devToolsEnhancer({}));
};
export default configureStore;
and my types/index.d.ts:
import { StoreEnhancer } from 'redux'
export {};
declare global {
interface Window {
store: {};
__REDUX_DEVTOOLS_EXTENSION__?: () => StoreEnhancer;
}
}
And finally my src/index.tsx:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import configureStore from "./store";
const store = configureStore();
if (process.env.NODE_ENV !== "production") {
window.store = store;
};
function Root() {
return (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<Root />
</React.StrictMode>
);
I will also attach screenshots of my file setup:
And my console error:
I am open to all suggestions, thank you!
The first issue here is that the store setup code is using outdated patterns and a lot of handwritten code. Today, you should be using our official Redux Toolkit package to write your Redux apps, and as part of that, RTK's configureStore API. It does all that same work with just a few lines:
import { configureStore } from "#reduxjs/toolkit";
const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer
}
})
That automatically combines reducers, adds the Redux DevTools extension setup, and adds the thunk middleware.
See our docs for guidance on setup:
https://redux.js.org/tutorials/quick-start
https://redux.js.org/tutorials/typescript-quick-start
https://redux.js.org/introduction/why-rtk-is-redux-today
https://redux.js.org/tutorials/essentials/part-2-app-structure
As for the specific error message you're seeing... the code seems like it would run. My guess is that something is wrong with the process.env.NODE_ENV check you added and so it's not assigning window.store.
RTK also works much better with TypeScript than legacy Redux code does.
I am new to React.js and was setting up base project at that I was getting one issue that my routing got changed but component doesn't load. After googling I found that I need to use ConnectedRouter. While setting up ConnectedRouter, I am getting console error: Could not find router reducer in state tree, it must be mounted under "router"
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ConnectedRouter, connectRouter, routerMiddleware } from "connected-react-router";
import { Provider } from "react-redux";
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import loginReducer from "./store/reducers/login";
import { watchLogin} from "./store/sagas";
import { history } from '../src/shared/history';
import { push } from 'react-router-redux';
import './index.css';
import App from './App';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const rootReducer = combineReducers({
login: loginReducer
});
const routersMiddleware = routerMiddleware(history)
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware, routersMiddleware];
const store = createStore(
connectRouter(history)(rootReducer),
{},
composeEnhancers(applyMiddleware(...middlewares))
);
sagaMiddleware.run(watchLogin);
const app = (
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
);
ReactDOM.render(app, document.getElementById('root'));
For the sake of helping future souls with this issue, it turns out that according to the linked github discussions, that version 5.0 of the history package is causing the issue and downgrading to version 4.10.1 solves the problem for me.
npm install history#4.10.1
https://github.com/ReactTraining/history/issues/803
https://github.com/ReactTraining/history/issues/804
Add router in your reducer with using connectRouter and history
Refer this link
https://www.npmjs.com/package/connected-react-router
import { connectRouter } from 'connected-react-router'
const rootReducer = combineReducers({
login: loginReducer,
router: connectRouter(history),
});
The main issue is the version of the history package, with react-router-dom v5 you need to use history v4 (the latest version of which is 4.10.1) - history v5 is only compatible with react-router-dom v6.
You have forgotten :
router: connectRouter(history),
in your combineReducers()
If you use immutable you should import ConnectedRouter from 'connected-react-router/immutable'.
I ran into the same issue.
I forgot to give the history as a parameter to my rootReducer, in my store initialization.
const store = createStore(
rootReducer(history), // <-- HERE
{},
...
)
When I navigate through the app the UI is stuck although the url changes.
I would like to integrate redux-persist on my current app but it eventually drove me to a strange bug to me.
Note: I use also the redux-saga as middleware on creating the store.
store.js
import { createStore, applyMiddleware, compose } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web and AsyncStorage for react-native
import createSagaMiddleware from 'redux-saga'
import rootReducer from "../reducers/index";
import rootSaga from '../sagas/index'
const persistConfig = {
key: 'root',
storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
const sagaMiddleware = createSagaMiddleware()
const middleware = applyMiddleware(sagaMiddleware)
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
persistedReducer,
{},
composeEnhancers(middleware)
)
export const persistor = persistStore(store)
sagaMiddleware.run(rootSaga)
export default store
window.store = store
When I comment in the Persist Gate component then the navigation works as intended.
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from 'react-redux'
import registerServiceWorker from "./js/registerServiceWorker";
import { PersistGate } from 'redux-persist/integration/react'
import store, { persistor } from './js/store';
ReactDOM.render(
<Router>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</Router >,
document.getElementById("root")
);
registerServiceWorker();
I hope I made myself clear!
Try wrapping your Router with the PersistGate. The order of these higher order components matters for React Router. The way you have it now, when you change the url it's not triggering a re-render, so swapping the order should fix the issue.
I'm getting this error on my index.tsx.
Property 'REDUX_DEVTOOLS_EXTENSION_COMPOSE' does not exist on type 'Window'.
Here is my index.tsx code:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import { createStore, compose, applyMiddleware } from 'redux';
import rootReducer from './store/reducers';
import thunk from 'redux-thunk';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, composeEnhancers(
applyMiddleware(thunk)
));
ReactDOM.render( <Provider store={store}><App /></Provider>, document.getElementById('root'));
registerServiceWorker();
I've installed #types/npm install --save-dev redux-devtools-extension and I'm using create-react-app-typescript. Thanks alot for any tips for what's going on in advance.
This is a special case of this question. Redux doesn't provide types for __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ because this function is exposed by Redux DevTools, not Redux itself.
It's either:
const composeEnhancers = window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] as typeof compose || compose;
Or:
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
}
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
This is already done by #redux-devtools/extension package that contains TypeScript typings. If it's installed, its imports should be used instead of accessing __REDUX_DEVTOOLS_EXTENSION_COMPOSE__ manually.
The most streamlined way to make this work with TypeScript is to use the redux-devtools-extension and install as a dev dependency as follows:
npm install --save-dev redux-devtools-extension
The next step for those new to redux and these developer tools was confusing and unclear. The docs all have code like the following:
const store = createStore(reducer, composeWithDevTools(
applyMiddleware(...middleware),
// other store enhancers if any
));
The problem is I don't have any middleware configured so this wasn't working. In it's most primitive usage, this is all you need:
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(myReducer, composeWithDevTools());
At this point if you click the extension in the browser and there is a valid redux store, you will be able to inspect the state.
This is an alternative approach to using (window as any) and also clears up just exaclty how to use the redux-devtools-extension in its minimal form.
This is how you can use redux-dev-tools in a typescript react application.
Create global Interface for the Window object:
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
}
}
Then, create composeEnhancers as follows:
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
Then create a store.
const store = createStore(rootReducers, composeEnhancers());
rootReducers - in my case refers to combinedReducers created in a surparate file.
Now you can use Provider as usual in React.js as:
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
All the code in the index.tsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import rootReducers from "./reducers";
import { Provider } from "react-redux";
import { createStore, compose, applyMiddleware } from "redux";
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
}
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducers, composeEnhancers());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();
My approach to the issue was the following:
export const composeEnhancers =
(window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
Working as a charm:
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
(window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__()
)
);
I had the same issue too however, I'm also using redux-thunk as a middleware. Running
npm install --save-dev redux-devtools-extension
and then adding in
import { composeWithDevTools } from 'redux-devtools-extension'
to index.tsx did the trick for me, as well as updating the store to
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))
My full index.tsx is below. Hopefully this will help anyone with the same issue that is using middleware such as redux-thunk
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './containers/App/App'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import authReducer from './store/reducers/auth'
import * as serviceWorker from './serviceWorker'
import { composeWithDevTools } from 'redux-devtools-extension'
const rootReducer = combineReducers({
auth: authReducer
})
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))
const app = (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
)
ReactDOM.render(app, document.getElementById('root'))
serviceWorker.unregister()
if any one still stuck into this issue I fixed it and this is my final store.js file
with following packages
1- Redux Thunk
2- Connected React Router
3- History
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import thunk from 'redux-thunk';
import {createBrowserHistory} from 'history';
import rootReducer from '../redux/reducers';
export const history = createBrowserHistory();
const initialState = {}
const enhancers = []
const middleware = [
thunk,
routerMiddleware(history)
]
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = (window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__() || compose;
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension)
}
}
const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
);
export default createStore(
rootReducer,
initialState,
composedEnhancers
);
Had same issue changed I just changed
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
to
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__() || compose
to get past an undefined apply issue when using createStore(reducer, initial state, compose(applyMiddleware
For anyone struggling with getting concurrently to work, the general advice I found is to replace your "client" script in package.json with:
"client": "cd client && npm start",
I tried this and I still got an error, so then I tried:
"client": "cd client && cd my-app && npm start",
This worked for me! The problem is that when you use create-react-app inside the "client" folder, there is an added level in between the client folder and your public and src folders which is called "my-app" by default. Using Brad's code, npm misses this folder so can't find the react files it needs to start your app.
In my case I have used react-redux-devtools. Try this solution may be it will help you to resolve your issue.
import { applyMiddleware, createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import createSagaMiddleware from "redux-saga";
import { rootReducer } from "../reducers";
import { AppState } from "#eneto/api-client";
import { initUserState } from "../../modules/users/user-reducer";
import { initUsersState } from "../../modules/users/users-reducer";
import { initListsState } from "../../modules/lists/lists-reducer";
import { initListState } from "../../modules/lists/list-reducer";
// initialValues
const init: AppState = {
currentUser: initUserState,
users: initUsersState,
lists: initListsState,
currentList: initListState
};
export function store(initialState: AppState = init) {
const sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];
return {
...createStore(rootReducer, initialState, composeWithDevTools(applyMiddleware(...middleware))),
runSaga: sagaMiddleware.run
};
}
#reactjs
I have been trying to setup redux-persist 5.9.1 with reactboilerplate 3.4.0 framework.
The error I receive seems to related to redux-immutable and I am unable to figure out right configuration.
Here is what I have done so far:
1. Install NPM
npm i -S redux-persist redux-persist-transform-immutable
package.json
"redux-persist": "^5.9.1",
"redux-persist-transform-immutable": "^5.0.0",
2. Setup Redux Persist in store.js
//store.js
import .... (other usual stuff)
import { persistStore, persistReducer } from 'redux-persist';
import storageSession from 'redux-persist/lib/storage/session';
import immutableTransform from 'redux-persist-transform-immutable';
const persistConfig = {
transforms: [immutableTransform()],
key: 'root',
storage: storageSession,
}
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
export default function configureStore (initialState = {}, history) {
// other usual stuffs ...
// I modified how store is created using persistedReducer
const store = createStore(
persistedReducer, // this line used to use createReducer() method
fromJS(initialState),
composeEnhancers(...enhancers),
);
const persistor = persistStore(store);
return { persistor, store };
// Please note, I have commented out hot reloading of reducers for now.
}
3. No change in reducers.js
4. Update App.js
import 'babel-polyfill';
import React from 'react';
// Added below
import { PersistGate } from 'redux-persist/es/integration/react';
// other usual setup
// Line below used to define just store but now we are defining persistor and store
const { persistor, store } = configureStore(initialState, browserHistory);
// Finally, update the render method:
const render = () => {
ReactDOM.render(
<Provider store={store}>
<PersistGate persistor={persistor}>
<Router
history={history}
routes={rootRoute}
render={
applyRouterMiddleware(useScroll())
}
/>
</PersistGate>
</Provider>,
document.getElementById('app')
);
};
And still no luck:
Error:
I think I do not have immutable maps configured right. Any help?
The way you doing is correct as documentation.
The problem is in here:
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
This const rootReducers = createReducer(); should not call like that, it will trigger the function. You should put like const rootReducers = createReducer; or better call like this:
const persistedReducer = persistReducer (persistConfig, createReducer)
Please see documentation, not call rootReducer for trigger function but pass it as variable.