DEV Community

Cover image for The most common problem in React code
Hans Ott (journy.io)
Hans Ott (journy.io)

Posted on

2

The most common problem in React code

I started playing with React about 5 years ago. The most common problem I've seen in React code is duplicate state.

Duplicate state always leads to problems.

So what do I mean with duplicate state?

Let's say we have a component that displays blogposts:

function Blogposts({ blogposts }) {
  return <ul>{blogposts.map(blogpost => ...)}</ul>
}
Enter fullscreen mode Exit fullscreen mode

If we want to add a search to this list of blogposts:

function Blogposts({ blogposts }) {
  const [filtered, setFiltered] = useState(blogposts)
  const [search, setSearch] = useState("")

  return (
    <div>
      <input
        type="text"
        onChange={e => {
          setSearch(e.target.value)
          setFiltered(
            blogposts.filter(
              blogpost => e.target.value === "" || blogpost.title.includes(e.target.value))
            )
          )
        }}
        value={search}
        placeholder="Search"
      />
      <ul>{filtered.map(blogpost => ...)}</ul>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Note: We want to show all blogposts if the search is empty (e.target.value === "")

This will work but there are some flaws with this approach:

  • If blogposts changes, we'll need to make sure that the filtered list is updated
  • If we want to persist the search parameter across pages (e.g. using a query parameter) we'll need to make sure the filtered list is initialised correctly
  • The component is hard to reason about

We'll have to make sure filtered is always up-to-date.

This becomes a lot harder with bigger components.

How can we fix this?

In this case we can calculate the filtered list if we have blogposts and search:

function Blogposts({ blogposts }) {
  const [search, setSearch] = useState("")

  return (
    <div>
      <input
        type="text"
        onChange={e => setSearch(e.target.value)}
        value={search}
        placeholder="Search"
      />
      <ul>
       {blogposts
         .filter(
           blogpost => search === "" || blogpost.title.includes(search)
         )
         .map(blogpost => ...)
       }
      </ul>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

We calculate the filtered list as part of the render cycle of the component.

Whenever the state changes, the component will re-render.

This means that we no longer have to keep filtered up-to-date:

  • We free our minds from having to think about filtered
  • The filtered list will always be correct
  • The component is easier to reason about

So here's my personal rule:

Always derive from the state if possible.

What about performance?

In most cases it's negligible because JavaScript is fast (unless you're computing heavy stuff).

You can use useMemo if you need too.

Let me know if this blogpost was helpful! 😊

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay