Discuss: React Hooks and Life After the Container-Component Pattern

Jen Chan - Nov 15 '19 - - Dev Community

I'm late to the party; I've been working with React for roughly 4 months and trying to build a project with Typescript and Redux. This past July, it seems like the core React team announced hooks and selector functions was the way to go.

Just so we're all on the same page with what I'm talking about, this LogRocket post describes the container component pattern as:

"...containers are the components connected to the Redux store using the `connect()` method. These containers get some part of global state as props ...and a dispatch method to initiate changes in global state."

I have been watching those Dan Abramov tutorials on lifting state and Egghead's React-Redux over and over.

At my last workplace everything was written in the container component pattern with connect() and React Redux. In an attempt to prove I can consolidate what I learned and couldn't learn, I'm trying to build a front end oriented expense splitter app (WIP, and any comments are welcome!).

Welcome to Hell when I try to get the value out of an input:
because the property value is buried 2 layers deep, nested in an array of objects.

handleItemChange = (event: any) => {
    const { parentNode, value, name } = event.target;

    this.setState((prevState: State, props: Props) => {
      return {
        items: items.map(item => {
          if (parentNode.id === item.id) {
            if (name === 'name') {
              item.name = value;
              return {
                ...item,
                name: prevState.inputValue
              }
            }
            if (name === 'cost') {
              item.cost = value;
              return {
                ...item,
                cost: Number(prevState.inputValue)
              }
            }
          }
        }
        )
      }
    })
  }
Enter fullscreen mode Exit fullscreen mode

I've heard that the above method is not optimal because:

  • this.setState() only works on changing the first level of the state object.
  • inline action methods like onHandleChange() are taking up a lot of lines
  • more experienced devs prefer to use a state immutability lib such as Immer.

In theory, here are some cases for hooks:

  • hooks gives you direct access to the state from wherever in the app
  • hooks allow state to be used in functional components so that business logic isn't limited to class components.
  • useEffect will replace lifecycle methods such as componentDidMount and componentWillUnmount, in short, saving lines of code and redundancy in having to write the "cleanup" code...

So, now that I've tried lifting state the hard way, how should I go about refactoring for the better? Where do I start?

Context API with useState()?

To keep using connect with useSelector, as demonstrated in this YouTube tutorial?

Write my own reusable hooks?

Fellow devs, I'd like to know:

  • Have you switched over to hooks? Why or why not?
  • How do you typically deal with updating a property of the state object that's nested several levels deep?
  • Following from the previous question: how do you manage shared state?
  • Let's say you are building an app for a pizza shop. Your inventory is updated by one reducer, and the user info is handled by a different reducer. What would you do when a property like updating or cancelling a user's order requires both states? (In Typescript, I would imagine I would create a type OrderState that includes both... but isn't that duplicating a lot of data that's already in the App state?)

Recommended Reading
Presentational-Container pattern
Making Sense of React Hooks
Rules of Hooks
Blogged Answers: Thoughts on React Hooks, Redux, and Separation of Concerns

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .