Ilya Karnaukhov
Ilya Karnaukhov

Reputation: 3975

React's useSelector with array of objects

Let's say I have a reducer with the following state:

messages: [
    {
        "id": "94",
        "characterId": "1",
        "text": "Uhm... Who are you?",
        "cloneId": "",
        "parentId": ""
    },
    {
        "id": "92",
        "characterId": "1",
        "text": "So what's with the whole E=mc2 thing?",
        "cloneId": "",
        "parentId": ""
    },
    {
        "id": "68-1",
        "characterId": "1",
        "text": "Oh no. Even now, we only have a small glimpse of the bottom of the ocean!",
        "cloneId": "",
        "parentId": "68"
    }
]

How can I make the Message component representing the message with id "92" rerender only when say the object with id "92" is updated?

This approach causes a rerender whenever any of the objects in the array change :/

const Message = () => {
   const data = useSelector((state) => state.conversationsData.messages.find((m) => {
       return m.id == '92'
   }))
   ...
}

Upvotes: 3

Views: 7603

Answers (2)

buzatto
buzatto

Reputation: 10382

redux presents some solutions about this question in the docs. you can pass shallowEqual (or other comparison method you prefer) as second argument like:

import { shallowEqual, useSelector } from 'react-redux'

const Message = () => {
   const data = useSelector((state) => state.conversationsData.messages.find((m) => {
       return m.id == '92'
   }), shallowEqual)
   ...
}

for more complex memoize situations you can use reselect library for memoizing along with redux.

Upvotes: 5

Stelios
Stelios

Reputation: 5

You can use "useEffect" hook for this.

  const [refresh, setRefresh] = useState(false)

  useEffect(() => {
    if (//check for particular message variable changes) {
    setRefresh(refresh=>!refresh)
    }
  }, [messages])


<MessageComponent refresh={refresh} />

With that approach message component will render only when refresh changes value

Upvotes: -3

Related Questions