Redux - Retrieve data from store and POST it - javascript

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!

Related

Redux Toolkit HMR in React Native does not update reducers

TL;DR: Configuring the Redux Toolkit store in React Native for HMR properly refreshes app on changes, but reducer behaviour does not change!
As seen in the React Native Reloading Announcement, HMR is supported for Redux within React Native, but the steps listed do not appear to work anymore. I have configured everything as mentioned in the announcement; however, the reducer reloading does not actually seem to change anything. When I edit a reducer, the app updates (reloading notification) but the reducer behaviour does not change!
// store/rootReducer.js
import { combineReducers } from "#reduxjs/toolkit";
import eventsReducer from "./slices/events";
import peopleReducer from "./slices/people";
const rootReducer = combineReducers({
events: eventsReducer,
people: peopleReducer,
});
export default rootReducer;
// store/index.js
import { configureStore } from "#reduxjs/toolkit";
import rootReducer from "./rootReducer";
const store = configureStore({
reducer: rootReducer,
});
if (process.env.NODE_ENV === "development" && module.hot) {
module.hot.accept(() => {
const newRootReducer = require("./rootReducer").default;
store.replaceReducer(newRootReducer);
});
}
export default store;
// App.js
import React from "react";
import { Provider } from "react-redux";
import store from "./store";
const App = () => {
return (
<Provider store={store}>
// ...ThemeProvider, Navigation scenes, etc
</Provider>
);
};
export default registerRootComponent(App);
Any ideas why this may be happening? I've been searching for related questions but cannot find anything from the recent past (ie. this year). Any older issues do not work either. My understanding is that I do not have to handle App HMR, as this is handled automatically by React Native. The announcement above makes it appear that adding HMR to Redux in React Native is super easy; however, it is has proven to not be the case.

Cannot access redux store in actions/api service (without connect() func)

I'm trying to fetch the token from my auth reducer in my app for making subsequent requests for more resources.
The problem is I can't access the store.getState() or store anywhere outside my components. Like actions/api service.
I remember earlier making an app where I was able to without any problems.
Here's a contrived example : https://stackblitz.com/edit/react-redux-app-1wxxab?file=index.js I've made a basic todo app and you can see in actions/index.js that when I console.log(store) I get undefined.
Update: I've updated the example to emphasise the problem, where I can't access it in a separate file api.js
Another Example: https://stackoverflow.com/a/43944684/1356046 they say it works like this but I'm not able to reproduce it.
Anyway to fix this and access the store state? Have tried everything since yesterday. Thanks.
Export store when you created it, then use it eg store.dispatch(action); or create api specific middleware
See What is the best way to access redux store outside a react component? for many examples
Update:
https://stackblitz.com/edit/react-redux-app-1mswrv
store.js:
import { configureStore } from "redux-starter-kit";
import rootReducer from './reducers'
export const store = configureStore({
reducer: rootReducer,
});
index.js:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './components/App'
import { store } from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
api.js:
import {store} from './store';
// Some promise which dispatches a fetch request after getting the token from the store
export const getSomething = () => {
console.log('store:', store);
return store;
}
Cloned your stackblitz and made the following changes:
In your api file do the following:
import store from './store';
Add a store.js with the content:
import { configureStore } from "redux-starter-kit";
import rootReducer from './reducers'
const store = configureStore({
reducer: rootReducer,
});
export default store;
And changed your index.js to:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './components/App'
import store from './store'
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
I would still opt for saving a token in local storage, if the user is logged in and opens another tab the user needs to log in again because the other tab has no access to the token, same when the user goes to another site and then back to your site.
If you are using redux-thunk and passing your api with withExtraArgument() to the thunk middleware passed to createStore() then you can use a lazy callback function to inject selectors for your API token (or whatever else you'd like) to a wrapped API helper function.
Personally, I prefer this approach as it decouples the api helper from redux. The API helper does not have to know about redux at all for this to work. Insread of imports, you simply inject the selector into the API helper, which then calls them when needed (long after the store is initialized).
api.js
// function accepting callback that returns a pretty
// standard post function
export const post = (getHeaders) => (url, body) => {
return fetch(url, {
method: 'POST',
headers: getHeaders(),
...
}
}
store.js
import * as api from './utils/api';
import { selectAuthHeaders } from './features/auth'
const store = createStore(
rootReducer,
initialState,
applyMiddleware(
thunk.withExtraArgument({
post: api.post(() => {
return selectAuthHeaders(store.getState());
}
})
)
)

Unexpected keys, "length", "action", "location" etc in Redux when using connectedRouter

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))
);

What is the use of autoRehydrate in redux-persist and why it was removed on v5?

I couldn't find anything on the GitHub page of ReduxPersist
I have a piece of code I'm trying to understand and as this autoRehydrate was removed, I would like to know how the code should be implemented with version 5 of redux-persist.
import { AsyncStorage } from 'react-native';
import { applyMiddleware, createStore } from 'redux';
import { autoRehydrate, persistStore } from 'redux-persist'
import thunk from 'redux-thunk';
import reducers from '../reducers';
const middleWare = [thunk];
const createStoreWithMiddleware = applyMiddleware(...middleWare)(createStore);
export default configureStore = (onComplete) => {
const store = autoRehydrate()(createStoreWithMiddleware)(reducers);
persistStore(store, { storage: AsyncStorage }, onComplete);
return store;
};
I've found some tutorials, but it just says this autoRehydrate must be there but doesn't explain what it actually does.
autoRehydrate means calling for the persist/REHYDRATE action to read the persisted state from the disk (which you have persisted before) which can be merged back to the original state.
In the migration guide from v4 to v5, they have introduced a PersistGate.
This delays the rendering of your app's UI until your persisted state has been retrieved and saved to redux.
Therefore all the rehydration actions will be handled by it under the hood.

cannot apply multiple middlewares using Redux applyMiddleware function

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!

Categories