Loading Stores in React-Redux - javascript

I am new to React-Redux, I have a app having all stores preloaded on the index.js file which is the entry point that renders the app . I have the following code in the page (a part of it).
if(Auth.isUserAuthenticated()){
store.dispatch(getProductCategories());
store.dispatch(getProducts());
store.dispatch(getAuctions());
store.dispatch(getAppSettings());
store.dispatch(getWalletTransactionHistory());
store.dispatch(getAllUsers());
store.dispatch(getParticipatedAuctions());
store.dispatch(getParticipatedAuctionsList());
store.dispatch(getWalletBalance())
}
store.dispatch(getHomePageAuctions());
store.dispatch(getAllPageAuctions());
store.dispatch(getPriceCards());
render(
<AppContainer>
<App store={store} history={history} />
</AppContainer>,
document.getElementById('app')
);
The action in the above are dispatched on every route change, But i Wanted it to dispatch only once on the page load . I even tried to put it on App component in ComponentDidMount() and also tried in putting it in constructor() of that component but no luck didn't work as expected and also searched google but no luck with exact match or similar to it

I suggest moving your store.dispatch calls inside App.js' componentDidMount. Since App.js will only mount once, they'll only fire once.

Related

How does React.suspense "handle" i18next backend loading?

I'm working with some pretty standard create-react-app boilerplate, which uses lazy loading and react-i18next as a translation library. This library uses i18next-http-backend to fetch the translation files from a remote API.
What i'm trying to understand, is how exactly React.suspense is able to "recognize" this asynchronous call, and show the fallback UI until it's done.
Index.ts file:
import "./i18n";//Notice this
const container = document.getElementById("root");
ReactDOM.render(
<StylesProvider jss={jss}>
<ThemeProvider theme={theme}>
<React.StrictMode>
<BrowserRouter>
<Router />
</BrowserRouter>
</React.StrictMode>
</ThemeProvider>
</StylesProvider>,
container
);
i18n file:
i18n
.use(Backend)
.init({
backend:{
loadPath: 'https://someRemoteApi/dictionary',
})
Router:
const Home = lazy(() => import("../../modules/home/Home"));
const Router: React.FC = (props) => {
return (
<>
<ErrorBoundary>
<Suspense fallback={<div className={styles.loader}><Loader /></div>}>
<Switch>
<ProtectedRoute exact component={Home} path="/"/>
...more routes
</Suspense>
</ErrorBoundary>
</>
);
};
With this setup, to my amazement, the fallback is rendered on the screen, until this backend plugin finishes its job. I'm trying to understand the mechanics of it, and whether this can be leveraged for other async operations.
the React docs clearly state:
React.Suspense lets you specify the loading indicator in case some
components in the tree below it are not yet ready to render. Today,
lazy loading components is the only use case supported by
<React.Suspense>:
Any clarification will be greatly appreciated.
The idea of Suspense is when a component throws a Promise (or anything that is called during the component’s render), React looks for the closest Suspense in order to display the fallback UI.
In your case, your components are using the useTranslate hook. When namespaces are not yet loaded, it throws a Promise and loads the namespaces. During the render phase, React catches the thrown Promise and looks for the closest Suspense component up the tree in order to display fallback UI.
This is a snippet from the hook useTranslation:
// not yet loaded namespaces -> load them -> and trigger suspense
throw new Promise((resolve) => {
loadNamespaces(i18n, namespaces, () => {
resolve();
});
});
You can check how the hook useTranslation works from here

Is it enough to use Provider one time?

In react-native when we use redux module we use createStore from 'redux'. And My question: is it enough to use <Provider/> one time which makes the Redux store available to the rest of our app.
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'
const rootElement = document.getElementById('root')
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
)
Or we must also add <Provider/> somewhere?
Once you create a store with redux with the reducers for example just like below:
const store = createStore(reducers, applyMiddleware(thunk));
Then you need to use <Provider> wrapper only once:
ReactDOM.render(
<Provider store={store}>
<App />
<Provider>, document.getElementById('root')
);
Later if you want to access any of the object from the store you need to use mapStateToProps in your components. If any modification is needed you need to create actions and dispatch them with mapDispatchToProps.
From the the documentation:
The option we recommend is to use a special React Redux component called to magically make the store available to all container components in the application without passing it explicitly. You only need to use it once when you render the root component.
Hope this helps.
Yep, you only need to use Provider once to wrap your whole application.
The question looks interesting. You need to understand how the store is available to every component wrapped inside the <Provider>.
When you wrap any React component inside <Provider store={store}> every component will have access to something called context, through which it is possible to share the data even it's not an immediate child.
Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree. https://reactjs.org/docs/context.html
As it states that context can be used in any child component without explicitly passing a prop.
The <Provider> exactly works the same way. And when you use the redux the <Provider> sets the context. And you need to use the connect() from the react-redux it uses the context set by the <Provider> to pass properties to your component wrapped in connect() HOC.
Hence you need to use the <Provider> only once in your application.

Passing props to props.children, receiving wrong props

App.js is the wrapper for my page, it's the layout enclosing the routes. Initially my routes were in App.js, but I want them in a higher order component so I can create routes which arent wrapped by App.
This is my current setup:
index.js
ReactDom.render(
<Provider>
<BrowserRouter>
<Route path='/' [...] /> // <-- Component which is NOT wrapped in App
<App>
<Route path='/about' component={About} /> // <-- I want About to receive the props from App
</App>
</BrowserRouter>
</Provider>
);
My App.js holds the Header, Sidebar and Footer component. App.js is the component I am exporting with connect(), I am mapping my redux state and actions with mapStateToProps and mapDispatchToPros in App.js
To pass the props down to, say, About, I tried different things with the same result, one of them being:
App.js
{React.cloneElement(this.props.children, {...this.props})}
However, the props I receive in About are completely different from the ones I am passing down. They are like this: (json)
{"match": {"path":"/about", "url": "/about", "isExact":true [...]}
So I am guessing those props come from the index.js, where my routes are. But how do I achieve what I am trying to do? Index.js is the component I am rendering the whole Application in. I am not exporting index.js.
Should I move the redux related stuff like mapStateToProps, mapDispatchToProps, connect(), ... to index.js? Or is there another solution?
Thanks!

How do you combine/compose multiple Higher Order Components (react.js)?

I've been looking into the concept of HOC's, but I'm not sure how to have multiple without just having an ugly deep nesting.
For example, if I wanted to add a library's HOC, like Redux provider or Apollo provider, then have my own HOC's and so on. Like below, is this not just really inefficient and ugly?
(Just an example, not actually using doing this at the moment. All theoretical.)
ReactDOM.render(
<ApolloProvider client={ client }>
<ReduxProvider state={ state }>
<MyHOC xyz={ abc }>
<App />
</MyHOC>
</ReduxProvider>
</ApolloProvider>,
document.getElementById('root')
)
As compared to
ReactDOM.render(
<CombinedHOCs client={ client } state={ state } xyz={ abc }>
<App />
</CombinedHOCs>,
document.getElementById('root')
)
But the only way I can think of this is looping through supplied HOC's which would again still have to loop (e.g. map) through everything (depending on what HOC does).
So am I looking at this the wrong way or is there no way to avoid this, assuming that those HOC's would be needed for the given component?
I think it's ok to nest HOC like you did in the example. But if you're using redux and Apollo you should integrate it and keep data in one store. You'll get rid of one nesting and this will let you better track the different events that happen in your app.
ReactDOM.render(
<ApolloProvider store={store} client={client}>
<MyHOC xyz={abc}>
<App />
</MyHOC>
</ApolloProvider>,
document.getElementById('root')
)

React components not updating from Redux state after Hot Module Reload

I am using react-hot-loader 3.0.0-beta.6 to hot reload react components. Reloading itself works well - i see the updated component immediately. Unfortunately, after successful reload, dispatching actions inside the application does not trigger rerenders any more and I need to do a full manual refresh to get the application working again. The dispatched actions update the redux store, but the components are not rerendered.
All the components I am using consist of a connected container and a stateless component.
What could be the reason for not rendering the updated state? How could I continue debugging?
MyComponent/container.js:
const mapStateToProps = state => ({
...
});
const mapDispatchToProps = dispatch =>
bindActionCreators({
...
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Component);
MyComponent/component.jsx:
const Component = ({ testProp1, testProp2 }) => (
<div onClick={testProp2}>
{testProp1}
</div>
);
Here is the successful update:
[WDS] App updated. Recompiling...
[WDS] App hot update...
[HMR] Checking for updates on the server...
[HMR] Updated modules:
[HMR] - ./source/modules/DropDown/index.js
...
[HMR] - ./source/modules/App/index.js
Render in the main.jsx:
const render = () => {
ReactDOM.render(
<AppContainer>
<Provider store={store}>
<MuiThemeProvider>
<App />
</MuiThemeProvider>
</Provider>
</AppContainer>,
eyeTalLayer
);
};
render();
if (module.hot) {
module.hot.accept('./modules/App', render);
}
There's actually a couple open issues in the React-Redux repo discussing similar behavior as of React-Redux 5.0. See react-redux#636 and react-redux#670.
I did a bit of research, and it looks like the components higher in the hierarchy are getting recompiled and hot-reloaded, but not the components lower in the hierarchy. Because v5 implemented a top-down subscription system, the lower components aren't aware that their subscription references are now stale. I haven't had time yet to try to figure out a good way to handle that.
Based on what I've seen, I believe that removing the use of React-Hot-Loader will work around the problem. You could just reload the entire component tree using "plain" HMR, and I see you've already got your code set up to do that. You'd lose the potential benefits of RHL trying to maintain component state, but the Redux connections should reset properly.

Categories

Resources