React Hook useEffect() - Run after mapStateToProps

767 views Asked by At

I am using hooks in my React application to handle state.

My application has notes that are associated to categories by categoryId.

Notes in a specific category are shown by mounting a NoteList component.

<NoteList categoryObj={categoryObj} />

The NoteList functional component

export const NoteList = (props) => {
  const [notesToRender, setNotesToRender] = useState(props.notes)
  
  useEffect(() => {
    console.log('I fired!', props.categoryObj.id, props.notes)
    setNotesToRender(props.notes)
  }, [props.categoryObj.id]);

  //...
  
  return (
    notesToRender.map((note) => {
      return <NoteListItem key={note.id} {...note}/>
    }
  )
}

const mapStateToProps = (state) => {
  notes: getNotesForCategory(state) // Selector that returns notes where note.id === props.categoryObj.id
}

export default connect(mapStateToProps)(NoteList)

Selector

export const getNotesForCategory = createSelector(
  [getNotes, getcategoryId],
  (notes, categoryId) => {
    const categoryNotes = notes.filter(note => note.id === categoryId)
    console.log('categoryNotes ', categoryNotes) // This log shows the correct notes
    return categoryNotes 
  }
)

I create notesToRender since I sometimes need to filter the notes before rendering them (that code is not shown here).

When switching between categories (props.categoryObj.id updates) the notes does not show correctly.

When loading the app the state is correct, but when switching between categories the useEffect somehow causes the state to be "one step behind".

  1. Category A - Inital load - OK
  2. Switch to "Category B" - console.log() shows the correct categoryId, but notes from Category A
  3. Switch to "Category A" - console.log() shows the correct categoryId, but notes from Category B
  4. Switch to "Category B" - console.log() shows the correct categoryId, but notes from Category A

... and so on

The console log from the selector shows the correct notes. The problem might be that mapStateToProps triggers after the useEffect? How can I make sure mapStateToProps triggers before the useEffect without causing unnecessary re-renders === only when props.categoryObj.id changes?

Kind regards /K

1

There are 1 answers

0
Kermit On

For me, the solution seems to be to change the useEffect() dependency from props.categoryObj.id to props.notes. My only hurdle now is how to compare two arrays of objects in the useEffect() dependency.

Things I have tested so far are:

  1. props.notes.length --> works but is not reliable - for obvious reasons :)
  2. ...props.notes --> works if array is not empty but may cause serious performance issues?

I have posted a new question here --> React useEffect() : Most efficient way to compare if two arrays of objects are equal