简体   繁体   中英

.map() is not a function when state is updated in Context

When updating the state, I'm getting the following error message noteList.map is not a function

I have the following setup

src/pages/index.js Where my DragDropContainer is being mounted

const Index = ({ data, location }) => {
  // instantiate a map of notes
  const noteMap = new Map()
  for (const brainNote of data.allBrainNote.nodes) {
    const key = "/" + brainNote.slug
    noteMap.set(key, brainNote)
  }
  return (
    <Provider noteMap={noteMap} openNotes={[data.brainNote]}>
      <DragDropContainer location={location}></DragDropContainer>
    </Provider>
  )
}

src/components/DragDropContainer.js

import React, { useContext } from "react"
import { DragDropContext } from "react-beautiful-dnd"
import ColumnDroppable from "../components/columnDroppable"
import { Consumer, Context } from "../utils/notesContext"

...

const DragDropContainer = ({ location }) => {
  const notesContext = useContext(Context)
  const { openNotes, setOpenNotes } = notesContext

  ...

  return (
    <div>
      <div>
        <div style={{ display: "flex" }}>
          <DragDropContext onDragEnd={onDragEnd}>
            <Consumer>
              {context => (
                <div>
                  {context.openNotes.map((noteList, ind) => (
                    <ColumnDroppable
                      key={ind}
                      index={ind}
                      noteList={noteList}
                      location={location}
                    />
                  ))}
                </div>
              )}
            </Consumer>
          </DragDropContext>
        </div>
      </div>
    </div>
  )
}

export default DragDropContainer

src/components/columnDroppable.js

const ColumnDroppable = ({ index, noteList, location }) => {
  return (
    <Droppable key={index} droppableId={`${index}`}>
      {provided => (
        <div ref={provided.innerRef} {...provided.draggableProps}>
          {noteList.map((note, noteIdx) => ( // when updated this line throws an error
            <NoteContainer
              key={note.title}
              title={note.title}
              note={note}
              noteId={note.title}
              location={location}
              slug={note.slug}
              noteIdx={noteIdx}
            ></NoteContainer>
            // <Note key={note.id} title={note.title} note={note} note noteIdx={noteIdx} />
          ))}
          {provided.placeholder}
        </div>
      )}
    </Droppable>
  )
}

ColumnDroppable.propTypes = {
  index: PropTypes.node.isRequired,
}

export default ColumnDroppable

src/utils/notesContext.js

export const Context = createContext({})

export const Provider = props => {
  const { noteMap: initNoteMap, openNotes: initNote, children } = props

  const [noteMap, setNoteMap] = useState(initNoteMap)
  const [openNotes, setOpenNotes] = useState([initNote]) // openNotes is a 2D array

  const setNoteAsOpen = slug => {
    // note map has the key set to the slug of a note
    const isNoteAlreadyOpen = openNotes.some(note => {
      return note.slug === slug.slice(1)
    })
    if (isNoteAlreadyOpen) return // note is already open

    const openingNote = noteMap.get(slug)
    setOpenNotes([...openNotes, openingNote])
  }

  const notesContext = {
    noteMap,
    setNoteMap,
    openNotes,
    setOpenNotes,
    setNoteAsOpen,
  }

  return <Context.Provider value={notesContext}>{children}</Context.Provider>
}

export const { Consumer } = Context

src/components/CustomLinkToDraggable.js This is where setNoteAsOpen() is being called from

...
export const LinkToDraggableNote = React.forwardRef(
  ({ to, onClick, onMouseLeave, onMouseEnter, ...restProps }, ref) => {
    const notesContext = useContext(Context)
    const { openNotes, setNoteAsOpen } = notesContext

    const onClickHandler = ev => {
      console.log("within onclick handler")
      ev.preventDefault()

      setNoteAsOpen(to)
    }
    ...
   return (
      <Link
        {...restProps}
        to={to}
        ref={ref}
        onClick={onClickHandler}
        onMouseEnter={onMouseEnterHandler}
        onMouseLeave={onMouseLeaveHandler}
      />
    )

After setNoteAsOpen() is called I noticed that noteList in ColumnDroppable is still of type array, but not 100% why it is throwing the error.

I also noticed that within setNoteAsOpen() the openNotes state is still the same after setOpenNotes() is called. As if setOpenNotes() didn't update the state. I'm not sure if this is related or causing the issue but figured I would point it out as well.

Thanks in advance!

As I know when react renders the component first time, the value of context may not be initialized, so map will not be a function, Try giving an empty array as the default value for context ,

{(context=[])=> (
        <div>
            {context.openNotes.map((noteList, ind) => (
              <ColumnDroppable
                   key={ind}
                   index={ind}
                   noteList={noteList}
                   location={location}
                 />
               )}

it should fix the problem

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