Skip to content

Non-listening hooks can cancel other listeners #135

@jckw

Description

@jckw

Thanks again for this library, it's been a great help in getting firebase to behave in our application.

I came across a bug related to having multiple useCollection hooks on the same collection.

The summary is: it appears that if one hook listens (i.e. passes { listen: true }) and another doesn't, but is called later, then the the first listener breaks.

I've put together a demo repo here that illustrates the problem: https://github.com/jckw/swr-firestore-listen-bug

It seems that we either need to commit to listening, or not, for a particular collection otherwise we risk having listening and non-listening hook calls which can lead to unexpected results.

const Main = () => {
  const { data, add } = useCollection<Note>("notes", { listen: true })

  const [newNote, setNewNote] = useState("")
  const submitNewNote = () => {
    console.log("Adding", newNote)
    add({ content: newNote })
    setNewNote("")

    /**
     * Notes on the effect: since the NonListenList doesn't listen to the collection,
     * neither will update when we trigger this. Interestingly, if you make a change and
     * the code updates with live reloading, then the listener works again.
     */
  }

  return (
    <div>
      <div>swr-firestore listening bug demo</div>

      <hr />
      <p>Listening</p>
      <div>
        {data?.map((n, i) => (
          <div key={i}>{n.content}</div>
        ))}
      </div>
      <hr />
      <p>Non-listening</p>
      <NonListenList />
      <hr />

      <div>
        <form
          onSubmit={(e) => {
            e.preventDefault()
            submitNewNote()
          }}
        >
          <input
            type="text"
            value={newNote}
            onChange={(e) => setNewNote(e.target.value)}
          />
          <button type="submit">Add note</button>
        </form>
      </div>
    </div>
  )
}
const NonListenList = () => {
  const { data } = useCollection<Note>("notes")
  // Adding a listener here makes the other listener work too
  // const { data } = useCollection<Note>("notes", { listen: true })

  return (
    <div>
      {data?.map((n, i) => (
        <div key={i}>{n.content}</div>
      ))}
    </div>
  )
}

export default NonListenList

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions