I've been going through some react - redux code and I'm stuck on the below code snippet
const mapDispatchToProps=dispatch=>({
addComment: (dishId, rating, author, comment) => dispatch(addComment(dishId, rating, author, comment))
})
I'm not that experienced in Javascript so it would be good to get a clarification on what this mapDispatchToProps method is accomplishing.
I know what this method is, I'm just confused on the Javascript part
mapDispatchToProps is the second argument of the connect function in redux. mapStateToProps is the first. You define mapDispatchToProps as a function of dispatch, which returns an object. The syntax const something = dispatch => ({ ... }) is a shorthand for an arrow function which returns an object. It is almost the same as
function mapDispatchToProps(dispatch){
return {
addComment: (dishId, ...) => dispatch(addComment(dishId, ...))
}
}
When you feed mapDispatchToProps to connect, and then wrap your component in that connect, it injects the properties and methods of the returned object into the component, as props. Hence the name mapXToProps. It will usually be used like this:
export default connect( mapStateToProps, mapDispatchToProps )(Component)
If you don't have a mapStateToProps, use null in its place. mapDispatchToProps allows you to inject your redux actions into your component, so that you can affect the redux store through the props on your component. mapStateToProps is similar - it allows you to grab items from your redux store, and assign them to props on your component. In your example, you would now be able to access this.props.addComment as a prop on your wrapped component. This is how you connect your components to the redux store, and how you can send and recieve data to the store.
Note that these are just naming conventions. You can actually name these functions whatever you want - but most people use mapStateToProps and mapDispatchToProps, as its pretty descriptive of what's hapenning. You can name them puppy and booya for all redux cares, so long as you feed them to connect properly.
Obligatory read the docs. Though to be frank when I was learning this, someone had to actually explain it to me too, but the docs are a great resource.
Related
I just started learning react hooks and react-redux hooks and as far I understood everything. But one thing is keep drilling my brain, so I would like to ask more experienced developers here.
If I have more robust app, where I intend to have Redux taking care of whole state and wanna use React hooks fro side effects, do I really need React Hooks?
I have separate functional layer (containers => where all the decisions are being made with redux) and displaying layer (components => where components are dumb and obtain just data they are suppose to render)
Whats bugging me is I make a API call in initial page loading and I would like to use useEffect hook, but im not conviced I should do that when I can useSelector from redux and useDispatch.
here is the code I would like to update into hook style:
const mapStateToProps = (state) => {
return {
cities: state.weather.cities,
}
}
const mapDispatchToProps = (dispatch) => {
const fetchForUpdate = (cities) => {
return cities.map((city) => {
return dispatch({ type: FETCH_START, payload: city.name })
})
}
return {
fetchForUpdate: fetchForUpdate,
}
}
const WeatherListContainer = (props) => {
const { cities } = props
const cityData = cities.map((oneCity) => {
return (
<WeatherItemContainer
name={oneCity.name}
data={oneCity.data}
key={oneCity.name}
/>
)
})
return <WeatherList item={cityData} />
}
const enhance: Function = compose(
connect(mapStateToProps, mapDispatchToProps),
lifecycle({
componentDidMount() {
console.log(this.props.cities, 'this.props.cities')
this.props.fetchForUpdate(this.props.cities)
},
}),
)
export default enhance(WeatherListContainer)
how can I fetch with redux hooks or react hooks? Or can I combine it? like use useEffect and then save it from local store to global store? Isnt it a bit ineffective?
Redux requires a middleware such as redux-thunk to dispatch asynchronous actions (an API call). If you plan on calling an API multiple times throughout your app, it makes sense to use redux-thunk and dispatch an asynchronous action, though this dispatch might still need to occur within useEffect/componentDidMount. If you only plan on a single API call, or if a specific side effect is unique to one component, there is no need to implement the middleware. For a single API call, you can send your request within useEffect/componentDidMount and then dispatch the result with a synchronous action to the redux store, without having to ever store it in component state.
https://redux.js.org/advanced/async-actions
I think there are some confusions. React hooks are used for sideEffects where redux hooks are for using the store more efficientl. Lets consider a scenario like bellow.
You are fetching a todo list from API and wanna use it all over the app. You have multiple components and you are gonna need the todo list in every component. In that case, you will call the api either using a middleware like redux-thunk or by other means like caling it in a useEffect( which is not a good practice) and save it to redux store using redux hooks. And whenever you redux store is updated, you will need to show the data in components. How will we do that? we will use react hooks to apply the sideEffects.
Here we will get the data from redux store using redux hooks. Than in a reactHooks like useEffect we will update a state of the component using useState. So here you can see, both reactHooks and reduxHooks are completely different in terms of functionality. one is storing and serving data which is reduxHooks and another one is showing the data when ever its added or updated which is reactHooks.
Hope you will find it understandable.
I'm trying to understand the connect() method of react-redux. Usually it takes two function as argument: mapStateToProps() & mapDispatchToProps(). I write a example for myself, here is connect() section of my User component:
//imports...
class User extends Component {
/* constructor, JSX, other functions... */
}
const mapStateToProps = (state) => {
return {
users: state.UserReducer
};
};
const mapDispatchToProps = (dispatch) => ({
deleteUser: (id) => dispatch(deleteUser(id))
});
export default connect(mapStateToProps, mapDispatchToProps)(User);
According to Docs I have taken the following two conclusions about mapStateToProps() & mapDispatchToProps():
mapStateToProps(): it makes that state available in our component. i.e. it is used to pass reducer to component.
mapDispatchToProps(): it maps component relevant functions to action functions, i.e. with this function We can perform the action that we want in our component.
is my conclusions correct?
React components accept data from outside via props.
maptStateToProps and mapDispatchToProps, literally, pass the selected state properties and actions that are needed inside your component as props.
The state values and actions passed to the component are available in the props of the component.
In your example, you can use this.props.users or this.props.deleteUser().
I'm getting my head around Redux and while I understand how it functions I'm not entirely sure if I'm using it correctly.
The Redux Documentation gives plenty of example on how to connect a functional component to my actions. But is there any way to call my action directly from within a function?
Is it possible to get something like this to work?
function mapDispatchToProps(dispatch) {
return {
saveUserData: user => dispatch(saveUserData(user))
};
}
function ConnectedUserInfo(){
console.log("fetching user info")
fetch('endpoint', 'headers',
}).then(response =>
response.then(user => {
this.props.saveUserData(user)
})
)
}
const getUserInfo = connect(
null,
mapDispatchToProps
)(ConnectedgetUserInfo);
export default getUserInfo;
I tried setting my redux state directly with saveUserData(user) but couldn't get the Store to change.
Connecting the two doesn't seem to do anything, unless I'm doing something wrong.
I'm unsure if this is the solution I'm looking for or if Redux wants me to mapDispatchToProps every time I want to change the state.
if you read the react redux documentation , you can see that connect method returns an HOC which accepts only react components.
in your code ConnectedgetUserInfo is not a react compoenent.
react-redux documentation: react-redux
react component defintion: https://reactjs.org/docs/react-component.html
also you have to name react component with starting character Capital.
I recommend instead of mapdispatch or mapstate use useDispatch and useSelector from react-redux for functional components
import {useSelector,useDispatch} from 'react-redux;
const dispatch=useDispatch();
const stateSelector=useSelector(state=>({
your states
}));
After watching a few Redux tutorials I still have a few questions:
After creating my store, i have:
ReactDOM.render(, document.getElementById('root'));
Going into the App component, I define:
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actions, dispatch)
}
Where do state and dispatch come from? Is this automatically referring to the store's state and dispatch since i connected it to my component?
One of my React components has a form which on submit, calls a function:
handleSubmit(event) { ... }
So in the constructor of that component, I have:
constructor() {
super()
this.handleSubmit = this.handleSubmit.bind(this);
}
Is calling super() always necessary when declaring a React class component?
Why do I need to do this type of binding there?
After submitting that form, I dispatch an action called addPost.
How does it "go" to the reducer? Is it just because the reducer was given when I created the store and using mapDispatchToProps(dispatch) I "let" Redux know which actions could be dispatched to that reducer?
The reducer simply returns a state object. Where is the logic that actually "saves" that state into the store? Is it hidden?
Yes, treat state and dispatch as references to your redux state and the dispatch function respectively.
React docs say:
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
Try an arrow function for your handler:
class MyComponent extends Component {
handleSubmit = () => {
// ...
}
}
The reducer was given to the store, the store was given to the react-redux <Provider> component, and the Provider component provides a React context where dispatched actions in descendant components get picked up by said reducers.
That logic is in the redux library.
Please check out our new official React-Redux docs . Specifically, you should read through connect: Extracting Data with mapStateToProps and connect: Dispatching Actions with mapDispatchToProps.
If you define a constructor for a class, and it extends another class, then yes, you need to call super() as the first line of the constructor - that's how ES6 classes are defined to work.
Redux only has a single reducer function. The insides of dispatch() look like this:
function dispatch(action) {
newState = rootReducerFunction(oldState, action);
subscriberCallbacks.forEach(callback => callback() );
}
You might want to read through the Structuring Reducers page in the Redux docs to get a better understanding of how and why reducers are normally split into smaller functions.
In most cases, the logic that combines the different "state slices" back together is in combineReducers(), because you used it to generate the "root reducer" function.
Where do state and dispatch come from? Is this automatically referring to the store's state and dispatch since i connected it to my component?
State is one of the hardest to understand topics and comes in front and center when we start concentrating on Redux. Each class-based component that we define has its own state object.
mapStateToProps is our ability to interface from the application level state down to the component level. Its where we sort of pluck properties off our state object and inject them into our components.
dispatch is how you change the state in your application, you dispatch an action.
In your implementation, you are using bindActionCreators, which turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.
I personally have not ever connected redux actions this way, so I had to look this one up.
Is calling super() always necessary when declaring a React class component? Why do i need to do this type of binding there?
Yes, React components always have to call super in their constructors to be set up properly.
For an in-depth explanation of this kind of binding trickery, begin with the React docs. If you are not so inclined, just know that in React, whenever you define an event handler that uses this, you need to add this.methodName = this.methodName.bind(this) to your constructor function.
I have redux store that looks something like this:
{
user: {},
alerts: [],
reports: [],
sourses: []
}
For each one of this parts of state i have a bunch of React Components wrapped in a container wich connected via react-redux. And has mapStateToProps like this
(state) => {alerts: state.alerts}
(state, ownProps) => {alert: _.filter(state, {id: ownProps.curId})}
Problem that when i for example launch some action for Alerts like CREATE_ALERT or EDIT_ALERT and redux state updated, ALL REACT COMPONENTS WILL RESPOND TO THIS CHANGE even ones that works with different parts like sources or reports.
My question: how to "bind" certain components to certain parts of a tree. So each container component WILL UPDATE ONLY WHEN APROPRIATE PART OF REDUX STATE UPDATED and ignore other changes.
Expected behavior
Dispatch CREATE_ALERT -> Alert reducer -> Redux store update -> ONLY Alert container component re-rendering.
When you are changing state in redux the whole state becomes just a new object.
Then your component is given by this new object (new reference) and re-renderes itself.
To fix this behaviour you need to add some logic to compare if your component got props with different value (not reference).
The easiest and fastest way is to use React.PureComponent. You can also override shouldComponentUpdate function and handle changes by yourself. But note that PureComponent works only with primitives (it does a shallow compare).
Check also Immutable.js which helps you with intelligent way of changing references of props.
if you use connect method, then pass only selected redux state to the component, this will prevent rendering of other components
example:
User Component:
const mapStateToProps = state =>({
users: state.users
});
export default connect(mapStateToProps)(User)
Alert Component:
const mapStateToProps = state =>({
alerts: state.alerts
});
export default connect(mapStateToProps)(Alert)
Check this out: Avoid Reconciliation
There explains what Neciu says.
Container components created with connect will always receive notifications of all updates to the store.
The responsibility for consuming these updates falls on the receiving connect component. It should contain the logic to extract the data relevant to it.