How do I specify a state form in a React / Redux app?

The thing that has puzzled me the most since I started reading about SPA is how to handle application state.

While I found most of the answers I was looking for in Redux, there are a few more things that I'm not sure how to handle.

One of these things is how to specify the shape of the "entities" that I want to use in my application. In other frameworks I've used in the past, I've seen extensive use of ES2015 classes for this purpose, but in React / Redux apps, object literals are by far the preferred way of expressing application state. I was reading about data normalization in the redux docs last night , and while it gave me great ideas on how to work with deeply nested objects, it left me with the feeling that something was missing and that this is how it should be stated in one place and as far as it is clear what is the structure / shape of the application state.

Take the sample data used in the article referenced above:

{
    posts : {
        byId : {
            "post1" : {
                id : "post1",
                author : "user1",
                body : "......",
                comments : ["comment1", "comment2"]    
            },
            "post2" : {
                id : "post2",
                author : "user2",
                body : "......",
                comments : ["comment3", "comment4", "comment5"]    
            }
        }
        allIds : ["post1", "post2"]
    },
    comments : {
        byId : {
            "comment1" : {
                id : "comment1",
                author : "user2",
                comment : ".....",
            },
            "comment2" : {
                id : "comment2",
                author : "user3",
                comment : ".....",
            },
            "comment3" : {
                id : "comment3",
                author : "user3",
                comment : ".....",
            },
            "comment4" : {
                id : "comment4",
                author : "user1",
                comment : ".....",
            },
            "comment5" : {
                id : "comment5",
                author : "user3",
                comment : ".....",
            },
        },
        allIds : ["comment1", "comment2", "comment3", "commment4", "comment5"]
    },
    users : {
        byId : {
            "user1" : {
                username : "user1",
                name : "User 1",
            }
            "user2" : {
                username : "user2",
                name : "User 2",
            }
            "user3" : {
                username : "user3",
                name : "User 3",
            }
        },
        allIds : ["user1", "user2", "user3"]
    }
}

      

How would you express the form of this data? Similar?

{
    posts : {

    },
    comments : {

    },
    users : {

    }
}

      

Or perhaps:

{
    posts : {
        byId : {

        }
        allIds : []
    },
    comments : {
        byId : {

        }
        allIds : []
    },
    users : {
       byId : {

        }
        allIds : []
    }
}

      

Well, it doesn't say anything about the actual shape of the objects that live inside each of the objects byId

, which is exactly what has been troubling me since I started learning a bit of Redux.

So the question is, is there any way / common practice that would allow me to express the form in the clearest way, specifically each of the properties of the objects that make up the state that will drive the store?

+3


source to share


3 answers


As the author of this section Structuring Reducers , since the actual content of your data items is entirely up to you and your expression. This is really more general Javascript "how can I express types?" question. There are static type systems such as TypeScript and Flow; documentation-based approaches such as JSDoc; runtime approaches like the React PropTypes library or tcomb; and schema-based approaches such as JSON-Schema. Any of these approaches is a valid way to document and apply data type definitions in an application.



Normalization is simply an approach to organizing these values, no matter how you choose to define their content.

+2


source


Assuming you are using plain JS, the easiest way is to use propTypes.shape .

 // An object taking on a particular shape
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),

      

If you are using propTypes, I suggest declaring the shape of all objects this way.



Benefits:

  • Explicit object forms.
  • You will be alerted quickly when unexpected object shapes pass.
  • You get advanced autocomplete support in modern editors like Webstorm .
  • Since the shape of an object is just an object, you can centralize the declaration to avoid repeating yourself.
  • You don't need to navigate TypeScript, thread, etc. to have explicit types and basic type safety at runtime.
+2


source


The best part about Redux is that you have a very clear separation of state concerns. Each reducer is responsible for its own piece of staff, and if you end up extending the reducer by adding more data / logic, you just need to break that reducer into smaller reducers.

Generally, I would avoid using arrays inside large data collections inside a reducer. Arrays are cool and give you a lot of nice functionality (sorting, filtering, shortening, etc.), but walking through them is expensive . If you can, use objects and use an id to identify your object, this way you will access the object using the fastest way.

Using your example, I would use the first approach:

{
  posts: {
    1554: {},
    1557: {}
  },
  comments: {},
  users: {},
}

      

If you need to keep track of list objects in an array, you simply create two new reducers inside the message reducer:

// postsReducer.js
import byId from 'postsByIdReducer'
import allIds from 'allIdsReducer'

export default combineReducers({
  byId,
  allIds
})

      

So your state will be like

{
  posts: {
    byIds: {},
    allIds: []
  }
}

      

+1


source







All Articles