what is the use of 'mapStateToProps' and 'mapDispatchToProps' in Redux? - react-redux

I can't understand the actual use of mapDispatchToProps, mapStateToProps so please explain with example.

mapDispatchToProps and mapStateToProps, are two API's.
mapStateToProps provides the store's current state object, using this we can filter and use the required part of state. We can also provide ownProps parameter which contains Component's parent supplied arguments. e.g:
const mapStateToProps = (state, ownProps) => {
return state;
}
mapDispatchToProps lets functions available inside our component's. So with actionCreators we can supply functions that could be used directly without dispatching them inside our Component e.g:
const mapDispatchToProps = dispatch => {
return {
login1: bindActionCreators(login, dispatch)
}
}
here login supplied to bind function is imported as * from an actions fil. e.g import login as * from 'filename'
Now Connect is an another API which is given by react-redux which provides the real glue and make things working e.g:
export default connect(mapStateToProps,null,mapDispatchToProps)(Login)
here Login is the Component(Class) to which we need to map to.
Hope this might clear, the difference feel free to ask if any more dobuts

Related

how to implement HOC as hooks with states

I want to make a HOC that returns a functional component instead of returning a class-based component (Because I want to update ContextProvider). Is it really possible to do it?
The problem with the functional component is that I need to define several states inside the functional component and based on that return the wrapped component but as we know the states could not be defined inside the return statement and if I move the useStates above the return basically this will not be HOC and any components that do use this way of implementation get "JSX element type '...' does not have any construct or call signatures" error.
Class-based:
const HOC(WrappedComponent)=>return class extends React.Component {
// do some state stuff also use componentDidMount
return(){
return <wrappedComponent {...someNewProps from state}
}
}
If I use hooks like this to define HOC
const HOC(WrappedComponent)=>{
// if I use useState stuff and useEffect here ( which should be outside return) then I get "JSX element type '...' does not have any construct or call signatures" error for any components that use such type of HOC
return <wrappedComponent {...someNewProps from state}
}

Trigger refresh of related components

I have a React-Redux app which displays a dashboard page when the user first logs on. The dashboard displays a number of statistics/graphs etc. which are components most (not all) of which are filtered based on a state site value. This site value is initially set when the user logs on and is derived from their profile.
The components mostly follow the pattern of using the componentDidMount lifecycle event to call a thunk method. Within the thunk method the site value is retrieved from redux state and passed in the database query. Reducer then adds results to state. Standard stuff. The redux state is fairly flat i.e. the state for the statistics/graphs etc. are not nested under the selected site but are their own objects off the root.
On the dashboard is also a dropdownlist which contains all sites. Initially this is set to the users default site. This dropdown is intended to allow the user to see statistics/graphs for sites other than their default.
What I would like is for all the (site specific) dashboard components to refresh when the user selects a different site from the dropdownlist. The problem I am having is how do I get these components to refresh? or more specifically, how to get their state to refresh.
UPDATE:
I tried two different approaches.
In the thunk action for handling the site change effect (changeSite) I added dispatch calls to each components thunk action. Although this worked I didn't like the fact that the changeSite thunk needed to know about the other components and what action creators to call. i.e. thunk action looked like:
changeSite: (siteId: number): AppThunkAction<any> => async (dispatch) => {
const promiseSiteUpdate = dispatch({ type: 'CHANGE_SITE', siteId });
await Promise.all([promiseSiteUpdate]);
dispatch(AncillariesStore.actionCreators.requestExpiring(siteId));
dispatch(AncillariesStore.actionCreators.requestExpired(siteId));
dispatch(FaultsStore.actionCreators.requestFaults(siteId));
dispatch(AssetsStore.actionCreators.requestAssetsCount(siteId));
dispatch(LicencesStore.actionCreators.requestLicencesCount(siteId));
dispatch(MaintenancesStore.actionCreators.requestMaintenancesCount(siteId));
dispatch(FaultsStore.actionCreators.requestFaultsCount(siteId));
}
Within a dependant component, included the Site value in the component properties, hooked into the componentDidUpdate lifecycle event. Checked if the Site had changed and then called the thunk action for updating the component state. I preferred this approach as it kept the business logic within the component so the changeSite thunk could now become a simple reducer call. An example of a dependent (site faults) component looks like this:
type FaultsProps =
{
faults: FaultsStore.FaultsItem[],
currentSiteId: number
}
& typeof FaultsStore.actionCreators;
const mapStateToProps = (state: ApplicationState) => {
return {
faults: state.faults?.faults,
currentSiteId: state.sites?.currentSiteId
}
}
class FaultyListContainer extends React.PureComponent<FaultsProps> {
public componentDidMount() {
// First load.
this.props.requestFaults(this.props.currentSiteId);
}
public componentDidUpdate(prevProps: FaultsProps) {
// Update state if site has changed.
if(prevProps.currentSiteId !== this.props.currentSiteId) {
this.props.requestFaults(this.props.currentSiteId);
}
}
public render() {
return React.createElement(FaultsList, {faults: this.props.faults});
}
}
export default connect(
mapStateToProps,
FaultsStore.actionCreators
)(FaultyListContainer as any);
Is #2 the best approach? is there a better way?

class property doesn't update with redux

Context
I've built an app that renders mails from your outlook accounts into a web page in react.
I'm trying to set a "viewed" boolean as a class property fed by redux store and change it from within the component (that change must impact in redux to manage that change on the overall app )
Problem
As you might see on below's code, i initiate the instance variable in the constructor with the given information from redux reducer,
I've tested with a bunch of console logs if the action creator successfully updates that information on the store and it actually does.
My problem is that my instance variable (this.viewed) isn't updating with redux's reducer information (that actually does update)
import React from "react"
import {connect} from "react-redux"
import { bindActionCreators} from "redux"
import * as QueueActions from "../redux/actions/actionCreators/queueActions"
class Mail extends React.Component {
constructor (props){
super(props)
this.id = props.id
this.viewed = props.mails.find(mail => mail.id = this.id).viewed
}
}
componentDidMount = () => {
this.props.queueActions.setMailToViewed(this.id);
}
function mapStateToprops () {
return {
mails : store.queueReducer.mails,
}
}
function mapDispatchToProps() {
return {
queueActions : bindActionCreators( QueueActions, dispatch ),
}
}
export default connect ( mapStateToprops, mapDispatchToProps ) (Mail)
Question
what am i doing wrong here?
why does the viewed property on redux updates but my instance variable that feeds from that very same information doesn't?
shouldn't this.viewed update whenever the props that provided the information update?
Can't i update this information from props without using a state?
I think the issue is because the assignment to this.viewed happens in the constructor, which is only called once. When the redux store updates, the component will get new props but the constructor will not be called again, so the value will not be updated. Hopefully these links will help explain the issue:
ReactJS: Why is passing the component initial state a prop an anti-pattern?
https://medium.com/#justintulk/react-anti-patterns-props-in-initial-state-28687846cc2e
I'd also recommend reading up on functional components v class components and why functional components are used alot now instead of class ones. A starting point:
https://medium.com/#Zwenza/functional-vs-class-components-in-react-231e3fbd7108
If you used a functional component, you could use the useSelector hook to access the store and update your components.
Hope this this useful, I'm quite new to react so apologies if you're looking for something more, but I hope this helps.

How to prevent re-rendering with useSubscription()?

Many of you might have heard of GraphQL. It provides QUERY and MUTATION. Also it supports SUBSCRIPTION as 100% replacement of web socket. I'm a big fan of GraphQL and hooks. Today I faced an issue with useSubscription which is a hook version of SUBSCRIPTION. When this subscription is fired, a React component is re-rendered. I'm not sure why it causes re-rendering.
import React from 'react'
import { useSubscription } from 'react-apollo'
const Dashboard = () => {
...
useSubscription(query, {
onSubscriptionData: data => {
...
}
})
render (
<>
Dashboard
</>
)
}
Actually useSubscription's API doc doesn't say anything about this re-rendering now. It would be really appreciated if you provide me a good solution to preventing the re-rendering.
Thanks!
Just put your subscription in separate component as this guy did, and return null, now your root component won't rerender
function Subscription () {
const onSubscriptionData = React.useCallback(
handleSubscription, // your handler function
[])
useSubscription(CHAT_MESSAGE_SUBSCRIPTION, {
shouldResubscribe: true,
onSubscriptionData
})
return null
}
// then use this component
<Subscription />
In my experience, there is no way to prevent re-render when receiving new data in onSubscriptionData. If your global data is used for calculations, you should use useMemo for you global variable. On the other hand, you should consider do you need put your variable in onSubscriptionData? Are there other ways? Did you use useSubscription in right component? If your have to do that, you have to accept extra rendering.
Hopefully, my answer is helpful for your situation.

How to use data returned from the asyncValidate function in react and redux?

I have created a form that is being validated using data from serve. If successful that validating function returns some data from server.
My Question is: How can I use those data from server!? More specific, how can I store them in redux store!?
Yes!
I've got the solution that is, The validation functions may also pass store dispatch function, that may be used to dispatch action and the data to the reducer so as to update the state!!
const asyncValidate = (values, dispatch) =>
{
axios(...).then(res => dispatch({type:'UPDATE_STATE', payload: res}))
}
thanks for all who viewed this question. Regards!!

Resources