Redux: mapStateToProps why second parameter ownProps - reactjs

I have seen many times people are connecting redux to component and they are using second parameter in mapStateToProps.
function mapStateToProps(state, ownProps) {
return {
rowData: state.table.rows[0],
};
}
Is in it useless? If child component has passed props from parent why should we map/pass them again in mapStateToProps?
What is the advantage of this?
Greetings

The usage of second parameter in mapStateToProps depends purely on the application. Mostly you may not need it, but in certain scenarios where the selector depends on the props to filter out the result, it is useful to use the props value from mapStateToProps
A scenario where your might need to make use of props are
Say you have a redux state data called used and you only need to show users in a specific region that comes as a prop to the component. You can make use of this prop value in mapStateToProps and return the filtered results instead of returning the entire result and filtering in render which might be a little less performant

You can avoid unnecessary renders, via retaining some possibly small subset of the store data with the help of some props.
For example, you have a slideshow application and Redux stores all the slides, and your component is responsible for a single slide. A prop value contains the slide number. By extracting the store data only for that specific slide, you make it easier for React and React-Redux to avoid unnecessary rerenders. Maybe the store changed due to some other user having edited another slide, in your collaborative presentation editor - no reason for your slide to get rerendered.
https://react-redux.js.org/api/connect#ownprops
Besides, Redux is global state, while your component can work with data just needed for that component. If you have plans to ever reuse your component, OR to ever consider switching from Redux (or even React) to something else, or just want to follow good practice by uncoupling Model from View, then it makes sense to separate your component from what's essentially a singleton global variable as much as you can. By carving out only the data you need, and possibly shaping it to the needs of your component, you performed a global Model to local ViewModel mapping, and it's easy to take your component elsewhere, without concern for what the global Model was when you implemented it. By using eg. Recompose, you can take it further and make things you can just move around freely.

There may overwrite the previous field, so it gives you a choice.
eg: return Object.assign({},state,ownProps);

The second arguments normally comes into picture when you want to extract the some values from the props or assign value in the return of mapStateToProps using your values in props, then the second argument comes into picture. A classic usage would be writing selectors which uses values from store and the props passed to the component.

Related

How to access data in child component of query called in parent component in rtk query?

How can I access the data of the query called in the parent component, inside a child component without prop drilling.
For example, if in parent.js I call the getPost query
const {data} = useGetPostQuery();
then how can I access this data further down the hierarchy?
There are two options I see:
The "right" answer way - is to use a selector from API slice to access the cached data which is already in rtk-q's Redux store. Let's say we have posts API slice definition. So we'll be able to access some particular cached post directly with a selector, provided by rtk-q:
.
const selectPost = posts.endpoints.getPost.select(postId);
selectPost - is a memorized selector, gererater by rtk-q for a particular postId. To fetch the data - that you'll need to pass the app state in, and it will return the expected post from the cache, that your parent component fetched before.
Inside the component it can be used with useSelector like:
const { data: post } = useSelector(posts.endpoints.getPost.select(postId));
Some more details here:
https://redux.js.org/tutorials/essentials/part-8-rtk-query-advanced#selecting-users-data
And a pretty straightforward way - is just to use the same query code in your child :).
Even it sounds weird\smelly - there is nothing wrong with it, due to you making your component standalone\decoupled, and it will get this data anyway - even will be used outside the parent component. But if it will be used in a case you described, as a child - it will just fetch data from the cache, with no real API call, so with no harm to performance. And it looks even more clear than selectors.
I prefer exactly this approach, and I feel it keeps the code more consistent - I'm just declaring that "I need that data" in a component, and don't care if it was fetched before or not, keeping all the components decoupled from knowing about any others component, making it cohesive.
It's somehow touched here:
https://redux.js.org/tutorials/essentials/part-8-rtk-query-advanced#cache-data-subscription-lifetimes
Offtopic bonus: In a case when you don't need the post data on a parent's component and want to fetch it only to improve responsiveness - you may use the usePrefetch hook. For example - on the "Edit" button hover, it will make an API call, put the data in the cache, so post will be available for children instantaneous.
More here:
https://redux-toolkit.js.org/rtk-query/usage/prefetching
If you want data to be available to all the rendered components then use Context. But, frequent changes in the context will cause permanence issues as the entire tree will get rerendered if the component is not designed properly.
Another option is to use Redux in the app to manage the states.
https://redux.js.org/introduction/core-concepts
Local storage is another option but will not recommend this.
The easiest way to send data from parent to child through props but if you want to do it without props you should use other stratigies like: localStorage,cockies or redux.

React Redux, component internal state sync

This is a bit complicated so I'll try to put it as simple as possible.
I have a pretty much complicated reusable component in my app.
Basically, it is a large table with many editing options.
Since this component should be reusable, my thought was that it should manage it's own state.
It also makes sense because this component's business logic is pretty much complicated, and by using redux, I'll probably have to repeat some crazy boilerplates.
On the other hand, this component should be able to have some default data loaded to, and finally, this component is in some cases a part of a form, so I sohuld be able to extract it's data and send it to the server.
Redux can really help with the last two tasks - if I had an easy way to store all component changes in the store, I could easily load the default data from there (because my component will be fully controlled), and it will also be easy to extract data from the store when sending to server.
Although, it has a lot of boilerplate, and I'm not feelinng comforotable to write a componenet specific logic in my reducers, since ideally, they could manage themselves.
Any more ideas about that?
I had one idea that seems to be working, though I am not sure how good it is:
Have a "dataKey" prop to handle default data prop changes, and derive the state from the data
Use some submit callback to extract the data and send to server
Any more thoughts will be very helpful, thakns!
It's hard to provide an extract answer as your question is kind of abstract. But since you are just looking for ideas, this is just an idea which you can try to incorporate with the actual use case.
In this kind of scenario, I would first distinguish my actual data and UI state. Then I will write my component as a controlled component of actual data with the usual value and onChange props. The UI state will be kept in the internal state of the component and it will either be derived from the initial props or initialized with a default value. When the user interacts with the component, if the change affects only the internal state, we can just use setState to update the state. If it affects data also, we can fire onChange prop also accordingly. This way we can keep the actual data in the redux store, but still, keep component specific logic in the component.
As an example, let's say we want to make a text label component with in-line/in-place editing support. I would still keep the props of this component similar to the default HTML input element as value and onChange. But the flag that indicates whether to render a text or input element with 'Submit' and 'Cancel' buttons will be kept in the component as isEditMode. Initially, we can always keep isEditMode as false. But when the user clicks on the text, we change it to true, so that component will render elements for editing and hide the label. While the user changes the text we can keep that intermediate value also in UI state. But when the user clicks the 'Submit', we can fire onChange with the new value in state and change isEditMode also to false. Likewise, we can keep the component as a control component but still use the component state to manage intermediate UI states.
Hope this helps!

Reselect - does it ever make sense to pass only part of the state to a selector

My store contains an array of goals. There's a Goal component which I connect to the redux store with connect() so it has a goal as its props.
The Goal component has children which all need the whole goal object to create derived data from. I want to use reselect to help extract how this data is derived, but it doesn't make sense to me to select the same goal from the whole redux store again, when I already have access to the goal.
So I'm currently passing in the goal object from the Goal component to its children and calling a selector on it as I do so.
This means the selector's argument is just one goal, a part of the state, rather than all of the state. All examples of how to use this use "connect" so the selector functions take in the whole of the state.
Does my approach make any sense? Or have I completely missed the point and I've no longer properly encapsulated the shape of the state tree?
any comments / advice would be appreciated
The purpose of the selector is to hold derived data so that your redux store doesn't have to. It's legit to pass in sub-pieces of the state tree:
const getThing = state => state.the.thing.I.care.about;
const getBoundaryConditions = state => state.the.boundary.conditions.man.whoa;
export const getTheThingICareAbout = createSelector(
[ getThing, getBoundaryConditions ],
(thing, conditions) => {
//do stuff to thing depending on conditions
return thing.beConditionallyAwesome(conditions);
}
);
Also, while it's possible to pass the goal object down to the children of the Goal component through props, it would be better to pass an id value (or something) down to the children through props and have the children get the corresponding goal from the state tree using connect() (see the powerful third mergeProps argument of connect() here which allows you to use passed in props ownProps alongside the whole state tree and dispatch - it can be quite handy).
This is better because the Goal component doesn't have to pass a big fat object down through a prop. Instead, the children components can select specific parts of the goal object that they care about in mapStateToProps() and keep the component props shallow as they should be.
...at least that's my opinion. Good luck with it!
You can choose to pass in a goal via props (from parent to child) - this meant the parent is "smart" (knows about the state) and the child if "dumb" (just renders what it is given in props).
Alternatively you can access the state (as much or as little of it as you like) in the child components.

Redux global solution for Cannot read property of undefined in mapStateToProps if store is not yet hydrated

After migrating to react redux land, I'm in love.. yet my heart breaks every time i try to render a route and gets a Cannot read property 'name' of undefined in the mapStateToProps function which is trying to extract a slice of state that is not loaded yet.
Example:
state = { posts:{ blog : {byId:{},ids:[]}, wall: {byId:{},ids{} } };
Say I do fetch all data from the server once the app starts up "index.js entry point". Based on the assumption that all data is loaded, I code multiple components to filter this data and work on it.
Trouble happens when a user opens the app and navigates too fast to a page where the data is not yet loaded. Then I get the hated error of "Cannot read property 'name' of undefined"
Example:
//route ::/posts/blog/1 has something like this
export default connect(
(state,prop)=>({
postId: state.posts.blog.byId[props.params.id].id
}))(props=><div>Post Id:{props.postId}</div>);
Now this components if loaded before blog store is populated it will give an error.
An option is to return a placeholder to connect and check first that post is loaded, or to use a magical proxy in initialState
initialState.blog = {byId:new Proxy({},{get:(obj,name)=>(name in obj)?obj[name]:{}}),ids[]}
//this will suppress error by returing an empty object if undefined byId
Is there any way i can REQUIRE a component to load its data by dispatching an action for example before it even renders?
What i want is something like what propTypes does except that it will defer loading the component or its connect function until the store confirms that it has finished loading.
Idea from propTypes:
Component.propTypes = {
dispatch:PropTypes.func.isRequired,
};
This will give an error if dispatch is not supplied as a prop for component
i want something similar but for store.
Example:
Component.requireData = (state)=>({
posts.blog:<placeHolder actionToDispatch="POST/BLOG/LOAD"/>, //if not posts.blog.isLoaded render placeholdercomponent insteed.
});
So it happens automagically if the required data is not loaded yet, the component will not render, and the placeholder will render in place dispatching an action that load the required missing data.
Whenever a component's render is called, it means the parent decided the component should exist. mapStateToProps is free to examine the state in any detail it needs to and produce any props from it as it sees fit. If a part of the state is missing, it can substitute some other props.
Some part of your system will have to decide when a place holder should be rendered rather than the data presentation component. The component that decides this may be the component itself or a parent. If it's a parent then you can make this component reusable.
No matter which way you turn this, you have to code the part that decides if all the data is ready. There's no magic. At the very least you'd need to pass a field name, but a function would be more flexible. At this point you may as well plug this function into the connect directly.
As such it seems to me that just writing a simple reusable parent component that takes a boolean prop that decides whether to show the child or a placeholder is not only a good and simple solution, but it seems to me that any other solution may not be substantially better or more "magical". Also "magic" is generally regarded as a bad idea these days because it implies a lack of transparency. By sticking to the React-Redux way, you are not adding hard to understand code.
Finally, don't expect either React or Redux to know what to do when your app doesn't provide the data that your app requires. Either don't require it or provide it. Creating a simple reusable parent component solves the issue by not requiring the data (and deciding what to do instead, which neither React, nor Redux, nor probably a third party library knows to decide).
Recap: create your own magic. It's simple, quick, and perfectly tuned to your needs.

ReactJS: Why is passing the component initial state a prop an anti-pattern?

I've created a small ReactJS dashboard with the help of SocketIO for live updates. Even though I have the dashboard updating, it bugs me that I'm not quite sure if I did it correctly.
What bugs me the most is the Props in getInitialState as anti-pattern post. I've created a dashboard that gets live updates from a server, requiring no user interaction beyond loading the page. From what I've read, this.state should contain things that will determine whether the component should be re-rendered, and this.props.... I don't know yet.
However, when you initially call React.render(<MyComponent />, ...), you can only pass props. In my case, I get all data from the server, so the initial props just end up in this.state anyway. So all of my components have something like this:
getInitialState: function() {
return {
progress: this.props.progress,
latest_update: this.props.latest_update,
nearest_center: this.props.nearest_center
}
}
Which, unless I've misinterpreted the aforementioned blog post, is an anti-pattern. But I see no other way of injecting the state into the Component, and I don't understand why it's an anti-pattern unless I relabel all of my props to prepend initial on them. If anything, I feel like that's an anti-pattern because now I have to keep track of more variables than I did before (those prepended with initial and those without).
Disclaimer: When I answered this question I was learning / trying to
implement vanilla Flux and I was a bit skeptic about it. Later on I
migrated everything to Redux. So, an advice: Just go with Redux or
MobX. Chances are you won't even need the answer to this question
anymore (except for the science).
Passing the intial state to a component as a prop is an anti-pattern because the getInitialState method is only called the first time the component renders. Meaning that, if you re-render that component passing a different value as a prop, the component will not react accordingly, because the component will keep the state from the first time it was rendered. It's very error prone.
And here is what you should do:
Try to make your components as stateless as possible. Stateless components are easier to test because they render an output based on an input. Simple like that.
But hey.. my components data change.. I can't make them stateless
Yes you can, for most of them. In order to do that, select an outer component to be the state holder. Using your example, you could create a Dashboard component that contains the data, and a Widget component that is completely stateless. The Dashboard is responsible for getting all the data and then rendering multiple Widgets that receive everything they need through props.
But my widgets have some state.. the user can configure them. How do I make them stateless?
Your Widget can expose events that, when handled, cause the state contained in Dashboard to change, causing every Widget to be rerendered. You create "events" in your Widget by having props that receive a function.
Ok, so now, Dashboard keeps the state, but how do I pass the initial state to it?
You have two options. The most recomended one, is that you make an Ajax call in the Dashboard getInitialState method to get the initial state from the server. You can also use Flux, which is a more sophisticated way for managing data. Flux is more of a pattern, rather than an implementation. You can use pure Flux with the Facebook's implementation of the Dispatcher, but you can use third-party implementations like Redux, Alt or Fluxxor.
Alternatively, you can pass this initial state as a prop to the Dashboard, explicitly declaring that this is just the initial state.. like initialData, for instance. If you choose this path, though, you can't pass a different initial state to it aftwards, because it will "remember" the state after the first render.
OBS
You are not quite right in your definitions.
State is used to store mutable data, that is, data that is going to change during the component life-cycle. Changes in the state should be made through the setState method and will cause the component to re-render.
Props are used to pass in imutable data to the components. They should not change during the component life-cycle. Components that only use props are stateless.
This is a relevant source on the "how to pass the initial state to components".

Resources