How to get application (redux) state in React component? - reactjs

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.

Related

Store with multiple reducers from different components. React / Redux

I have a store that needs to connect to different components. I created 3 different slices and wanted to make a dependency with the store.
When I hook all of three reducers :
export const store = configureStore({
reducer : {
home : homeSlice,
about : aboutSlice,
review : reviewSlice,
},
});
I get the next error :
Invalid hook call. Hooks can only be called inside of the body of a function component.
You are somehow using store incorrectly.
The Store needs to be passed to the Provider (which wraps all the components inside app.js).
import {store} from 'your_path'
const App = () => (
<Provider store={store}>
<MyApplication />
</Provider>
)
After that, you can already use Redux inside components.
To change states, use the useDispatch() hook,
and to get the state useSelector().
Here is a link to documentation about hooks in React-Redux https://react-redux.js.org/api/hooks
As in react, documentation hooks can be called only inside of a functional component. The code you provide to merge reducers is correct. You need to use useSelector and useDispatch hooks inside the component functions to retrieve the value or dispatch an action respectively. What is the main issue you are facing?

Fetch data for the entire app without depending on component logic

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

Difference between using React-Redux <Provider> and connect()

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

Getting a Cannot update during an existing state transition message after library updates

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

Manage eslint errors with Redux Actions

I am using react-redux for managing my presentation & container components. And i am passing a list of actions to my presentation component from my container component in the below manner :-
function mapDispatchToProps(dispatch) {
return bindActionCreators({ ...ActionList1, ...ActionList2 }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(PresentationComponent1);
So i have list of actions as specified in my action file which i import and pass it on to my presentational component. Within my presentational component, i trigger these actions based on the user interaction with the screen. For e.g.
onRadioButtonChange(event) {
this.props.changeRadioButtonValue(event.target.value);
}
In this way, there are a bunch of actions which i call from my presentational component. Now, i am using Airbnb's eslint config as base. Now, one of the rules is to validate the props validation, the failing on which it throws the below error :-
changeRadioButtonValue is missing in props validation
Now, what is the recommended way to tackle this?
Write proptypes for each of the actions? Is there a way we can specify the entire action file in the proptypes validation, rather than individual action?
Or disable prop validation in eslint?

Resources