There are X routes in the frontend made with React-router and each of them drives to a component.
No matter which route is visited, I need to use some data from an api.
This data is constant through the application. Using Redux I could dispatch an action FETCH_DATA in each React component and manage the logic of fetching in Redux actions.
However, this looks repetitive to me because I would be writing the same logic through all the React components that need data: look for the the data in the store. If it's there take it. If it's not there, dispatch FETCH_DATA.
What is another approach?
You can call that api in the App.tsx i.e. your first component to be rendered in the application. This is the component which actually holds the Routes also.
Consider the following code as an example and change it according to the need of your application:
class App extends React.Component {
ComponentDidMount() {
this.props.callTheApiHere()
}
render() {
return (
<Routes history={this.props.history} />
)
}
}
export default App;
Now each component that any of your Route render have to just get the data from the redux store using mapStateToProps in react-redux Connect
GraphQL offers an elegant solution for this requirement of sharing data across components belonging to different routes.
More information:
https://www.youtube.com/watch?v=p_kqcGW1jkY
Apollo GraphQL (React) Data sharing across components
Related
I am confused about why a create-react-app has both
import {store} from './our-redux-store'
const app = () => {
return (
<Provider store={store}>
<WholeAppGoesHere/>
</Provider>
)
}
versus using connect with a component like so:
import {connect} from 'react-redux';
class MyComp {
// ...
}
export default connect(
mapState,
mapDispatch
)(MyComponent);
do we need both? what's the difference?
The provider is a component. You use the provider at the top of the component chain where your application starts. You place it so it wraps your entire application. Within this container, you pass the store. This allows any child component to access the store.
connect() is used as a higher-order function that you wrap around specific components. Connect in essence maps state data contained within the store to the props within that specific component. Maybe it helps to think of connect() as a way an individual component gets the specific data it needs from the global store
Provider is a part of React Context functionality. By assigning your store there, it makes the specific value of store available to all consumers of that context.
connect() on the otherhand is a higher order component that injects your mapped states and dispatches into the props of your base component. To do so, it calls the Consumer part of this api to access the store context.
Edit: https://react-redux.js.org/using-react-redux/accessing-store#understanding-context-usage
I know that the Router component, say BrowserRouter creates a history object for keeping track of paths and so on, and that a Route component renders its view only when its path matches the current location, which I assume is read from the history. My question is how does the Route component get access to the history object that is created by the BrowserRouter. Is there some under the hood communication going on that is making this possible?
This is a context api 'magic'.
<BrowserRouter/> renders <Router/>:
class BrowserRouter extends React.Component {
history = createHistory(this.props);
render() {
return <Router history={this.history} children={this.props.children} />;
}
}
<Router/> renders <RouterContext.Provider/>:
<RouterContext.Provider
children={this.props.children || null}
value={{
history: this.props.history,
<Route/> uses <RouterContext.Consumer> to provide access to data from provider.
Using context api allows to provide data/methods many levels down the tree without the need of passing down props expliticely (on each level). You can read more about this on docs or search for tutorials.
Have a ReactJS + Redux + Saga application that was recently updated to use the latest (or close to latest) versions of the respective JS libraries. After the library updates (no code changes) and running the application, I immediately see the "Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state." warning message in the console. It looks to be triggered by redux when I invoke the dispatch function (which then calls a function in Provider.js, then goes through react-dom, and then in turn writes the warning message. Again nothing in my code has changed, and my code is essentially built using stateless functions.
Not sure how to go about figuring out what is causing this warning-- although the app still runs ok as expected. Using React 16.8.6, react-redux 6.0.1, react-router-dom 5.0.0, redux 4.0.1, redux-saga 1.0.2, and connected-react-router 6.4.0.
Below is a sample page that would cause the warning message:
import React from 'react'
import {connect} from 'react-redux'
import {links} from '../links'
import {notify} from '../notifications'
const Home = props => {
const {dispatch} = props
return (
<main>
<p>
Go to Details...
</p>
</main>
)}
const dispatcher = dispatch => {
dispatch(notify(links.HOME))
return {dispatch}
}
export default connect(null, dispatcher)(Home)
You cannot call to dispatch inside the disaptcher function.
react-redux's connect parameters are:
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
mapDispatchToProps is what you called dispatch. These params are eventually run as functions that called in the render loop of the connected component. When you dispatch in the render loop it changes the state of a React component (looks like it's the Provider), which is forbidden by React.
Solution
Move the dispatch(notify(links.HOME)) to lifecycle method. For example you can add to the Home component (this will require to rewrite the Home component as an extension of React.Component class:
componentDidMount() {
dispatch(notify(links.HOME))
}
UPDATE
If you want to do this with classless component see that question
I'm new to react and redux. Now I build my first application that is connecting to an api server with redux. In my reducer file I'm setting the new state.
My question is how can I access that state value in a component?
You need to connect your component to the Redux store via the connect component, which is provided by Redux. The connect component requires a function to be provided called mapStateToProps. This function will tell Redux which items from the Redux state you want in your component.
It will look something like this:
function mapStateToProps(state) {
return { yourStateKey: state.yourStateKey }
}
export default connect(mapStateToProps)(YourComponent)
You can learn more in the appropriate section in the Redux docs.
I am trying to write a react native application making use of both redux and react native navigation. However, I do not actually want to save my navigation state in redux. So I just want to keep them separated from each other. I currently have the StackNavigator and that is wrapped in a connect which then is wrapped by the provider.
const mapStateToProps = state => state;
const mapDispatchToProps = dispatch => dispatch;
// need this Higher Order Component so you can pass properties through the root stack
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(RootStack);
export default class App extends Component {
render() {
return (
<Provider store={Store}>
<AppContainer />
</Provider>
);
}
}
Is this implementation possible?
Yes, this is possible, and in fact, encouraged.
Quotation from react-navigation docs:
Some folks like to have their navigation state stored in the same place as the rest of their application state. Think twice before you consider doing this, there is an incredibly good chance that you do not need to do this!. Storing your React Navigation state in your own Redux store is likely to give you a very difficult time if you don't know what you're doing.
By default, Redux and React-Navigation have nothing to do with each other, and in its next release (Fall 2018) support for integrating React-Navigation into your redux state will not be documented or encouraged at all.