Redux Toolkit HMR in React Native does not update reducers - javascript

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.

Related

How to use RTK query and redux thunk in same react app?

I have requirement where I have to use RTK query for data fetching and Redux-thunk for global state management. For the same I have created 2 separate stores, one for RTK and another for redux. Now I am facing issue as we should not have 2 stores in our application.
store 1:-
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import combineReducer from './combineReducer';
export const configureStore = () : any => {
const middleWares = [thunk];
const middlewareEnhancer = applyMiddleware(...middleWares);
const enhancers = [middlewareEnhancer];
const composedEnhancers: any = compose(...enhancers);
const store = createStore(combineReducer, composedEnhancers);
return store;
};
store 2:-
import { configureStore } from "#reduxjs/toolkit";
import { setupListeners } from "#reduxjs/toolkit/query";
import { postApi } from "../services/posts";
export const store = configureStore({
reducer: {
[postApi.reducerPath]: postApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(postApi.middleware),
});
setupListeners(store.dispatch);
App.tsx:-
const App: React.FC = () => (
<Provider store={store}>
<Provider store={rtkStore}>
<Suspense fallback={<div>Loading...</div>}>
<BrowserRouter>
<Routes />
</BrowserRouter>
</Suspense>
</Provider>
</Provider>
);
I am sure, there is something fishy in this. Any solution for requirement would be appreciable.
Redux Toolkit comes with thunk per default. You do not need to set it up. RTK Query internally is based on thunks. You cannot have multiple Redux stores in one application.
Just create one store with configureStore, also add your other reducers there and use that for everything.
Generally we recommend in the Redux style guide to use Redux Toolkit for all your Redux logic, as helpers like createSlice massively reduce your boilerplate code and guard against most common bugs.
This is the default recommendation for over two years now.
I would highly recommend you to read the official Redux Essentials tutorial if you haven't already.

Heroku app accessible only on device which I created it

I want to deploy my app, but I have some problems with it.
Here's some details:
Free plan on heroku
All I can see on other devices is the backgrond image/collor/pattern
Errors on other devices(mostly connected with redux):
On Firefox(on Windows):
On Chrome(on Windows):
On Internet Explorer I didn't see any console errors( but it only shows background).
ps. I have one additional question about ssl certificate. How to add it(step by step).
Thanks for suggestion. I found the problem, that I forced devtools in production here's the fixed part.
store.js
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; //that's the solution
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(
applyMiddleware(...middleware)
)
);
export default store;

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

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.

Promise Redux : TypeError: next is not a function

I have a little app running on React + Redux with redux-promise middleware in order to deal with promise API call. I would like to manage the state of each api call (loading, success & error). So, as the official documentation says I change the applyMiddleware argument.
import React from 'react';
import ReactDOM from 'react-dom';
import promiseMiddleware from 'redux-promise';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reducers from './reducers';
import routes from './routes';
const createStoreWithMiddleware = applyMiddleware(
promiseMiddleware({
promiseTypeSuffixes: ['LOADING', 'SUCCESS', 'ERROR'],
}),
)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory} routes={routes} />
</Provider>
, document.querySelector('.container'));
But when I change the appyMiddleware my app doesn't work anymore, I have this error showing on console:
TypeError: next is not a function
If I change back this line, everything works again as intended.
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware)(createStore); // App works again
What's wrong?
Thank you,
I strongly believe that the way you create the store is incorrect.
In creating a store, there are 3 arguments,
createStore(reducer, preloadedState, enhancer) {...}
(1) reducer -> (required)
(2) preLoadedState -> (optional)
(3) enhancer -> (optional) // This is where your applyMiddleware should be passed. Hence, the minimal creation of a store is,
const store = createStore(() => {});
To answer your question, creating a store with a middleware should be,
const store = createStore(yourReducer, {}, applyMiddleware(promiseMiddleware))
or simply
const store = createStore(yourReducer, applyMiddleware(promiseMiddleware))
// This should also work because if the 2nd parameter is a function then it will be treated as the enhancer.

Categories