I am trying to write a React app and I am trying to use ConnectedRouter:
https://github.com/supasate/connected-react-router
It's a Redux binding for React Router.
I am getting the following error:
Now I think this is probably related to this question's accepted answer:
Redux: Unexpected key found in preloadedState argument passed to createStore
However unlike there when trying to pass default, I actually probably want these in my combine reducer.
Here's my current code in my reducers/index.js:
export default history =>
combineReducers({
router: connectRouter(history),
search,
profile,
color,
categories,
coordinates: LocationReducer,
idprovider,
firstFavorite,
analytics,
sidebar,
messages,
total_messages,
onesignal,
tokens
});
And in my store.js:
import createRootReducer from "./reducers/index";
I'm not quite sure what the correct solution is here, as ConnectedRouter doesn't seem to do anything with these values.
What is the correct solution?
EDIT: In my example bellow I used syntax used in connected-react-router v4, but my example was definitely wroking.
There was an update in usage for v5/v6, if you are using version>=5, try to migrate my example into it:
https://github.com/supasate/connected-react-router/blob/master/FAQ.md#how-to-migrate-from-v4-to-v5v6
You probably do not intialize the store correctly.
Try this:
reducers/index.js
export default combineReducers({
// router reducer will be added automatically by connectRouter in store.js
search,
profile,
color,
categories,
coordinates: LocationReducer,
idprovider,
firstFavorite,
analytics,
sidebar,
messages,
total_messages,
onesignal,
tokens
});
store.js
import {connectRouter, routerMiddleware} from 'connected-react-router';
import {createBrowserHistory} from 'history';
import reducers from './reducers';
const history = createBrowserHistory(history);
const store = createStore(
connectRouter(history)(reducers),
applyMiddleware(routerMiddleware(history))
);
Related
I'm going through many Redux-tutorials, and something that confuses me, is the fact, that when creating a Redux store with a combined reducer, there often is the reference to a name rootReducer as the root reducer, although it has never been actively named.
Is this something like a default behaviour that is taken advantage of? Because it seems to be working like that.
I suspect, it has something to do with the way, the reducers are combined and exported
with
export default combineReducers.
Here is an example:
./reducers/combined.js :
import { combineReducers } from 'redux';
import filmReducer from './filmReducer';
export default combineReducers({
media: filmReducer
});
then, in ./store.js :
import { createStore, applyMiddleware } from 'redux';
...
import rootReducer from './reducers'; // why can 'rootReducer' be imported?
Anyway, after a long search, I still couldn't find any reference to this phenomena.
You reducer is exported as a default and default imports can be given any name
You could have also called it reducer too. It just depends on what you want to call it
import reducer from './reducers';
Had you not exported the reducer as default but a named export you are expected to use the same name while import
For Example:
import { combineReducers } from 'redux';
import filmReducer from './filmReducer';
export const reducer = combineReducers({
media: filmReducer
});
will be imported as
import { reducer } from './reducers/combined';
P.S. You must also note that you can import component from index.js within a directory without specifying the index file in import path. However for any other file name you need to mention the file name for import
Please refer the MDN docs on import
Reducer is a function that takes previous state, the action, then returns a new state.
(previousState, action) => nextState
In redux, there is only one reducer function. It handles all the actions and returns the new state. This reducer function is usually called rootReducer, but you can call it whatever you want. When you create the store, the first argument is the root reducer.
createStore(reducer, [preloadedState], [enhancer])
(check out the doc: https://redux.js.org/api/createstore)
As your app grows more complex, you'll want to split your reducing function into separate functions, each managing independent parts of the state.
The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.
This is from the official documentation to explain what is combineReducers: https://redux.js.org/api/combinereducers
In your code:
export default combineReducers({
media: filmReducer
});
combineReducers returns a reducer function as mentioned above. export default will then export the function so that you can import it from ./store.js
If you want to know more about how import/export works, check this https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
Newbie at Redux back here again, thanks to the question I posted recently I have been able to use redux-logger to keep track of everything that is updated through the store and knowing that every re-render is being happening at my reducer.
The question is still the same, as now that I can see in my log what is happening and everything is being stored in the store, but how can I retrieve it and post it? I need to post through the API to the backend and do some calculations.
The log of my application https://imgur.com/a/JCPklMV
store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './RootReducer';
export default function configureStore() {
return createStore(
rootReducer,
applyMiddleware(thunk)
);
}
Full code at Sandbox https://codesandbox.io/s/elated-goldberg-1pogb
Thanks in advance!
I have a search bar that when you click on it, using redux bring the results and display a list of product. But the url stay the same how can I make the url show the keyword I use to search like this:
http://localhost/seach?q=keyword
I don't if this is the best way. But I'm using history.pushState() to change the url without reload.
You can use react-router to control the router of the application, and use react-router-redux to connect the route to the redux.
```
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { routerMiddleware, push } from 'react-router-redux'
// Apply the middleware to the store
const middleware = routerMiddleware(browserHistory)
const store = createStore(
reducers,
applyMiddleware(middleware)
)
// Dispatch from anywhere like normal.
store.dispatch(push({
pathname: 'search',
query: {
q: keyword
}))
```
Can anyone help me out with the right redux store configuration?
I am trying to configure as follows,
configureStore.js
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers';
let middlewares = [thunk, logger]
const configureStore = () => {
const store = createStore(
rootReducer,
applyMiddleware(...middlewares) // I also tried with applyMiddleware(thunk, logger)
);
return store;
}
export default configureStore;
And I import this module main js file and use as follows,
index.js
import configureStore from '../stores/configureStore';
const store = configureStore();
// And other DOM render code follows...
But is seems not working and the following error displays in the web console,
Error: Uncaught TypeError: WEBPACK_IMPORTED_MODULE_0__compose.a.apply(...) is not a function
File in which the error is:
I am following official docs of redux, redux-thunk and redux-logger but unable to make it work.
Another note: It works fine when I remove any one of thunk and logger from the middlewares list.
UPDATE: I got temporary fix
Downgrading redux from 3.7.2 to 3.5.2 works fine.
I still wonder why it is the problem with latest version of Redux. I tried to add more information related to the issue and looking for solution for future upgrades.
Thanks!
You just made a tiny mistake.
From the official docs, here is the signature of createStore:
createStore(reducer, [preloadedState], [enhancer])
You mixed up the order of the arguments, passing your enhancer function (applyMiddleware) where the function is expecting the preloadedState. You need to pass in an argument in between the rootReducer, and the applyMiddleware function, in order to satisfy the signature.
Hope this helped!
I would like to pass router params into Vuex actions, without having to fetch them for every single action in a large form like so:
edit_sport_type({ rootState, state, commit }, event) {
const sportName = rootState.route.params.sportName <-------
const payload = {sportName, event} <-------
commit(types.EDIT_SPORT_TYPE, payload)
},
Or like so,
edit_sport_type({ state, commit, getters }, event) {
const payload = {sportName, getters.getSportName} <-------
commit(types.EDIT_SPORT_TYPE, payload)
},
Or even worse: grabbing params from component props and passing them to dispatch, for every dispatch.
Is there a way to abstract this for a large set of actions?
Or perhaps an alternative approach within mutations themselves?
To get params from vuex store action, import your vue-router's instance, then access params of the router instance from your vuex store via the router.currentRoute object.
Sample implementation below:
router at src/router/index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes
})
export default router
import the router at vuex store:
import router from '#/router'
then access params at vuex action function, in this case "id", like below:
router.currentRoute.params.id
Not sure to understand well your question, but :
This plugin keeps your router' state and your store in sync :
https://github.com/vuejs/vuex-router-sync
and it sounds like what you are looking for.
To my knowledge ( and I've looked into this for a project I'm working on ) no, there is not.
The simplest way to do this is to abstract route fetching or anything you want to do to a service and use it in your vuex file or if you use modular approach import it in you actions.js file.
so paramFetching.js file would look like this:
export default {
fetchRouteParams: function() {
// do fetching
// you should return a promise
}
}
Then import that into your vuex
import service from 'paramFetching.js'
And then make an action like so
...
fetchParamsAction: function({commit}) {
service.fetchRouteParams()
.then( (response) => { // stuff gottten from service. you should o your commit here } )
.catch( (error) => { // error handling } )
}
And then just dispatch this action and everything will be handled in an action. So it kinda isolates that from the rest of the code.
This is just a general idea. I'm sorry if it's not clear enough. If I can help further, please ask.
You can use this function to get params into Vuex
import router from './router';
router.onReady(()=>{
console.log(router.currentRoute.params.sportName)
})