简体   繁体   中英

React state changes, but component doesn't re-render

Any help would be appreciated. I'm getting my data from an external database and feeding it in with observables. The component updates when the players state changes, but it doesn't update when the monsters state changes.

I can see that the state is correct and populated with non-zero data by debugging the component with the React Developer Tools. If I force players to update again, it does re-draw the monsters correctly, but setMonsters isn't itself causing a re-render.

export default () => {
  const [players, setPlayers] = useState({})
  const [monsters, setMonsters] = useState({})

  useEffect(() => {
    const playersSub = players$.subscribe(setPlayers)
    const monstersSub = monsters$.subscribe(x => {
      console.log('should be re-rendering...')
      setMonsters(x)
    })

    return () => {
      playersSub.unsubscribe()
      monstersSub.unsubscribe()
    }
  }, [])

  return (
    <Section style={{ backgroundColor: medium, borderRadius: '.5rem', flex: '1 0 0' }}>
      {Object.entries(players).map(([key, x], i) => {
        if (!x.investigator) return <div key={key} />
        return <Player player={x} key={key} />
      })}
      {Object.entries(monsters).map(([key, x]) => {
        console.log('what is going on?')
        return <Monster monster={x} key={key} />
      })}
    </Section>
  )
}

Weirdly when I refresh the page it updates and shows the correct render for just a fraction of a second before it closes.

EDIT

Okay, I "fixed" it, but I'd still like to know what is causing the issue if anyone can shed some light on this problem for me.

The fix is just as bizarre as the problem to me, and I consider myself fairly familiar with React and RxJS.

I changed the subscription to this.

  useEffect(() => {
    const playersSub = players$.subscribe(setPlayers)
    const monstersSub = monsters$.subscribe(x => {
      setMonsters({ ...x })
    })

    return () => {
      playersSub.unsubscribe()
      monstersSub.unsubscribe()
    }
  }, [])

And now it works as intended. That doesn't seem like it should do anything.

React uses Object.is() equality (referential) to determine whether state has been updated. We should not directly mutate state, as if you're sending it the same reference, it just won't know.

You can either send an entirely new copy, as you did in your working version, or use the syntax that takes an updater function to set state from current state.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM