Search code examples
javascriptreactjsreduxreact-reduxflux

React-Redux design pattenrs: Should a "deep" component be wired to Redux, or receive props from parent components?


I'm building some instant messaging app using React and Redux in the frontend. I have components like "Main"(initializes the web socket and renders other components), "Chat", "FriendsList" and "Friend"

I often find my self wondering, if i should wire a child or a grandchild to Redux directly(assuming it needs it), or to pass those props from the parent/grandparent.

For example, i render "Chat" in the Main component this way:

 <Chat
    onTyping={this.onTyping}
    onSubmitMessage={(value) => { this.submitMessage(value) }}
    messages={this.props.messages[this.props.activeFriend] || []}//This comes from Redux
    isMessagingAvailable={this.isMessagingAvailable()}    
  /> 

As you can see, i'm passing a "messages" prop, which in turn comes from Redux. I could of course just wire Chat to Redux independently.

The question is then, whether there is some convention regarding the best practice in this situation. Should every component that consumes global state be wired to Redux directly?


Solution

  • TL;DR;

    The idea behind modular design is to have as many generic component as possible.

    These components should be independent of outer world(i.e. Redux Store).

    In my understanding, the structure of any app should be like:

    • You have root level component that serves their purpose. Like: input box
    • Then you have a composite component, that will consume these root components. Like handling error labels along with input.
    • Then you have form Higher Order Components(HOCs). These are business components and have context of whats going on. These components should have access to Redux store.

    Example:

    Lets create a form with basic info:

    • First Name
    • Last Name
    • Age
    • Email

    For such form, you need following components:

    • Text input component
    • Number input component with text prevention/validation logic.

    You can use textInput for FirstName, lastName and email. So if you directly tie it to store, you are making it dependent to your own redux structure. So these components cannot be used anywhere else.

    Hence, best idea is to create dumb components that accept props and do their thing.


    Your usecase.

    You have following modules:

    • Main
    • Chat
    • FriendsList
    • Friend

    In future, you plan to add few more modules:

    • AI / Bot chat
    • Group Chat

    Now the chat window for individual, bot and group chat would be similar but the store structure will be difficult. Especially for Group chat.

    So how do you decide, which component should bind to store?

    You should create nested component hierarchy for you view and create an HOC for your business modules. This way, your view components are not dependent on store. Your HOC will provide data and thats all it does.

    So in your case, you will have following HOCs:

    • Direct Chat
    • Bot Chat
    • Group Chat
    • Contacts
    • Dashboard

    And you can have following view component:

    • Chat component: Used for all chats types.
    • Contact component: Used for friend list/ contact view
    • List component: Used for browser contact, add members view and manage members view.