Redux denormalizr - reactjs

I'm using a thunk for getting data async from an API, this is nested data like this:
{
person: {
id: <id>
services: [{
id: <id>,
leader: {
id: <id>,
name: <name>
}
},...]
}
}
Now, this gets normalized into this (let's imagine we have a bunch of persons and stuff):
{
result: <person-id-1>,
entities: {
person: {
<person-id-1> : {
services: [<service-id-1>,...]
},...
},
service: {
<service-id-1>: {
leader: <leader-id-1>
}
},
leader: {
<leader-id-1>: {
name: <name>
}
}
}
}
Ok, so, now I've to get this entity full into my component, the question is, What's the best way to do this?
Should construct this entity back into the function mapStateToProps
Should I do it into the render() method,
In any case, what's the best approach for this. I've seen the reselect library but I still not very sure that this is the solution for getting the entity back together. Also there are other libraries to denormalize the entities, but not sure if I should use them.
Should I just create a nested component for each nested entity?
Thanks!

Yes, the standard approach is to do any data shaping for a given component in its mapState function, using Reselect-based selectors to memoize the process. You may also want to look into the Redux-ORM library, which provides a very nice abstraction layer over managing normalized data in a Redux store. I use it for both data de-normalization/selection in thunks and mapState functions, and immutable data updating in reducers.
There's also a good article on this topic at https://medium.com/#adamrackis/querying-a-redux-store-37db8c7f3b0f .

You should check this video made by the Redux author and the shopping cart example in redux repo. reselect helps you to create an memoized, composable selector functions. read more here. I hope it will help you.

Related

I want to access a specific indexed object from object of array of REDUX STORE in REDUX REDUCER

I want to access a specific indexed object from object of array of REDUX STORE in REDUX REDUCER. But what would be the best and simplest way to do it.
This is the object (array of object)
const formData = [
{
name : 'Aman jat',
gender : 'male'
},
{
name : 'Ravina',
gender : 'female'
}
]
This is what i want to do ::
const reducer = (state=formData,action) => {
if(action.type=='INSERT_INFO') {
return {
...state,
state[0].name : action.payload_name1 <<<< this is my problem
}
}
else
return state
}
If I'm reading this correctly as "you want to update the name property of the first object in the state array", you probably want to do
return [
{ ...state[0], name: action.payload_name1 },
...state.slice(1)
]
Seeing that you are just learning I have the usual PSA though: This is a pretty old style of redux that we are not really encouraging to teach any more. If you are following a tutorial teaching you this, that tutorial is probably very outdated. Please follow the official redux tutorials over at https://redux.js.org/tutorials/index for up-to-date information.
In modern redux with the officially recommended redux toolkit (and only there, not with the style you are using!), this could actually be written as
state[0].name = action.payload_name1

React.JS Performance Boost Overall

What would be some general tips & tricks you personally know and tested that work for improving performance in a React.js component ?
Personally the best tip I could provide is to avoid writing logic that updates your component-state to frequently. You do not want your component to constantly be calling this.setState({}) because it creates a sort of distorted lag which may affect your application both visually and performantly.
Definitely avoid writing stuff like:
componentDidUpdate(){
this.setStatE({
field: this.props.newData
})
}
But while also on that topic, make use of your lifecycle methods, particularly componentDidMount() and componentDidUpdate() these are incredibly useful for controlling logic inside your component. In a way they can also enhance your component by giving it a sort of breathing mechanism for processing data.
Lastly, this is more-so a preference, but if you want to have good code-readability, I would suggest creating a function to generate your mark-up instead of writing it directly inside your render-method.
Considering the following code:
import React from "react"
class Example extends React.Component{
state = {
tests: [{id: 1, name: "test1"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}]
}
render(){
const tests = this.state.tests
return(
<div>
{ tests.length > 0 && tests.map((test) => {
return <div>{test.name}</div>
})}
</div>
)
}
}
This code is perfectly fine as is, but you can make it easier to read for someone else just by making another function for your mark-up.
Revised:
import React from "react"
class Example extends React.Component{
state = {
tests: [{id: 1, name: "test1"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}]
}
createTests = () => {
const tests = this.state.tests
if(tests.length > 0){
return tests.map((test) => {
return <div>{test.name}</div>
})
}
}
render(){
const tests = this.state.tests
return(
<div>
{this.createTests()}
</div>
)
}
}
Does the same thing, but now it's very clear what we're trying to accomplish inside our render method.
There are couple of things we have implemented.
We used one plugin to figure out how many wasted render we have and this was 60 %.
To address this there are couple of things we have done.
1.We can use life cycle hook up to figure out is there any change in property.
2.Minimize the parent child relation ship between component.
3.If we are using any kind of redux to manage the state then we should be having top level component connected to store and pass the data as props to child component.
4.for Asyc call care should be taken to place if we want it in compoentDidMount or ComponentWillmount as if the data of asyc call is required in child component or not.
There are many options to optimize your React Application, too much to cover on one answer. My advice here is, start you App, open DevTools and go to Audit, start the Lighthouse test. The Test will show certain actions which can be done to optimize your code and also ressources to read about.
If you have more concrete questions ask then. Your current question is kinda too much to cover in one answer. Or post code, which you want optimized.

redux, normalizr, access store mapDispatchToProps

If I have a data object like below
{
items: [
{id: 1, selected: false},
{id: 2, selected: false}
]
}
Running this through the normalizr would get me something like
{
entities: {
1: {selected: false},
2: {selected: false}
},
result: {
items: [1, 2]
}
}
Typically I would have an Items component that maps the state to props like this:
const mapStateToProps = (state) => {
return state.result;
};
The problem I have is on the Items component, I would have a save button that needs to send the state of the store to the server.
I haven't seem to be able to find a good way to access the store to denormalize the data before sending it to the server.
1) I prefer not to include the Entities in MapStateToProps because there is no need for the items component to know about it.
2) MergeProps also seems suboptimal due to performance issues.
Right now I'm accessing the store directly by simply importing the store and accessing it in my dispatch methods which seems to work, but that breaks the separation of concern, is there a better way to do this?
Judging from the description of your problem, I believe you send the store's data by a method inside Save button component, or another React component. If you do that, you must expose the sending data to that component no matter what.
An alternative solution is to handle the API call by a middleware. Libraries such as redux-saga or redux-thunk can handle your case neatly. They are designed to handle async flows, and provide access to the store.

Accessing a List of Objects when your State is Normalized / Flat

Redux recommends your state be flat per here: https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape
So say my state was like this:
{
selectedPlaylistIndex: 0,
pageDict: {},
playlistDict: {},
playlistList: [] // holds IDs from playlistDict
}
a sample Playlist Object would look like:
{
id: someId,
active: false,
pageList: [], // holds IDs from pageDict
}
If I want to state create a Container for displaying the "pageList" of a Playlist object, I pass in the Playlists' "pageList" property as a list of the full Page objects (as opposed to the IDs). I feel like it's an expensive operation as anytime pageDict, playlistDict, playlistList, or selectedPlaylistIndex get updated, it will be rendered and the function will run.
Is there a more elegant / better way of doing this? I feel like I'm missing something.
// Expensive Operation; Want to Find Better Solution?
getSelectedPlaylistPageObjArr() {
const { selectedPlaylistIndex, pageDict, playlistDict, playlistList } = this.props;
return playlistDict[ playlistList[ selectedPlaylistIndex ]].pageList.map( id => pageDict[id] ) : [];
}
render() {
return (
<Playlist
pageObjArr={this.getSelectedPlaylistPageObjArr()}
/>
);
}
const mapStateToProps = ( state ) => {
return {
pageDict: state.entities.pageDict,
playlistDict: state.entities.playlistDict,
playlistList: state.entities.playlistList,
selectedPlaylistIndex: state.application.selectedPlaylistIndex,
};
};
Generalising, you're asking how to handle relational data.
Last time I had to deal with relational data I integrated redux-orm library. It's a small and immutable ORM to manage relational data in your Redux store.
So let's say your business logic is as follows 1 Playlist has many Pages, then in order to get the Pages of the selected Playlist (by playlist's id), it would be computed with redux-orm as follow:
const getSelectedPlaylistId = state => state.application.selectedPlaylistIndex
const getPlaylistPages = createSelector(
orm,
getSelectedPlaylistId,
({ Playlist }, playlistId) => {
return Playlist.withId(playlistId).Pages.all().toRefArray();
}
);
Once you invoked getPlaylistPages the result will be cached and recalculated only when one of the accessed models are changed.
Also if you don't want to use redux-orm (let's assume your app doesn't have a lot of models or any other reason), then you can just use reselect library, that will cache your performance cost computations.
As I already mention I had such an experience, and my thoughts and conclusions are summarized in the following SO question: How to deal with relational data in Redux?

Efficiently computing derived data from react props

We are in the process of implementing performance optimizations in our react/redux application. Part of those optimizations included introducing reselect. This worked nice for data that is derived directly from the state. but what about data that is derived from other props?
Example:
We have 3 components Feed FeedItem and Contact (Contact is a component for displaying a users contact information).
a FeedItem gets an object that represents an item in the feed, one of the properties of a feed item is an actor object. This object is like a user but a bit different (this sucks but can't be changed). This means that if I want to render a Contact for this actor I need to create a new object that maps the properties from an actor to a user. Creating a new object on every render is a performance anti pattern because we are using shallow equality checks.
e.g code:
<Contact
user={{
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
}}
</Contact>
Is there a pattern for solving this? reselect only supports derived data from redux state, this is basically derived data from props.
You can pass whatever you want to reselect's selector methods. It doesn't have to be state and props. That just happens to be it's most common use case. You can call one if it's generated selectors with any number of arguments.
Here's one way you could use it:
function convertActorToContactUser(actor) {
return {
photoUrl: actor.photo.smallPhotoUrl,
Id: actor.id,
Name: actor.name,
};
}
class ActorContact extends Component {
constructor(...args) {
super(...args);
this.getUser = createSelector(
() => this.props.actor,
convertActorToContactUser
);
}
render() {
return <Contact user={this.getUser()} />
}
}

Resources