简体   繁体   中英

I am getting this error in the console : Cannot read property 'some' of undefined

TypeError: Cannot read property '' of undefined ı have no idea why ı am getting this error while I do check the code below everything seems fine :( trying to learn the way how react works :) So what is the purpose of this since all the properties I wrap on contextprovider suchas contacts loading and the functions I need

import React, { useState, useContext } from 'react'
import ContactContext from '../context/contactContext'

export default function ContactForm() {
  const name = useFormInput('')
  const email = useFormInput('')

  const contactContext = useContext(ContactContext)
  const { addContact } = contactContext

  const onSubmit = () => {
    addContact(name.value, email.value)
    name.onReset()
    email.onReset()
  }
  return (
   SOME HTML CODE HERE
  )
}

//contactState.js
import React, { useReducer } from 'react'
import _ from 'lodash'
import ContactContext from './contactContext'
import ContactReducer from './contactReducer'

const ContactState = props => {
  const initialState = {
    contacts: [
      {
        id: '098',
        name: 'Diana Prince',
        email: 'diana@us.army.mil'
      }
    ],
    loading: false,
    error: null
  }

  const [state, dispatch] = useReducer(ContactReducer, initialState)
  const [contacts, loading] = state
  const addContact = (name, email) => {
    dispatch({
      type: 'ADD_CONTACT',
      payload: { id: _.uniqueId(10), name, email }
    })
  }
  const delContact = id => {
    dispatch({
      type: 'DEL_CONTACT',
      payload: id
    })
  }
  return (
    <ContactContext.Provider
      value={{
        contacts,
        loading,
        addContact,
        delContact
      }}
    >
      {props.children}
    </ContactContext.Provider>
  )
}
export default ContactState

//contactReducer.js
export default (state, action) => {
  switch (action.type) {
    case 'ADD_CONTACT':
      return {
        contacts: [...state, action.payload]
      }
    case 'DEL_CONTACT':
      return {
        contacts: state.contacts.filter(
          contact => contact.id !== action.payload
        )
      }
    case 'START':
      return {
        loading: true
      }
    case 'COMPLETE':
      return {
        loading: false
      }
    default:
      throw new Error()
  }
}

//contactContext.js
import { createContext } from 'react'
const contactContext = createContext()
export default contactContext

In your reducer, when adding a contact, you're spreading the wrong state key. This should fix it:

case 'ADD_CONTACT':
  return {
    contacts: [...state.contacts, action.payload]
  }

I can't see where you are using ContactState in your app. If you don't use it and render your ContactForm component with it then you can't reach any context value. You should render it as:

<ContactState>
  <ContactForm />
</ContactState>

in a suitable place in your app. Also, you can't get contacts and loading like that:

const [ contacts, loading ] = state;

state is not an array, it is an object here. You should use:

const { contacts, loading } = state

You can find a simplified version of your code below. I removed/changed some parts in order to run it as much as possible. You should fix your reducer as @Asaf David mentioned in their answer, but this is not the main problem here. After fixing the context issue, you can try to fix your reducer.

About your questions, if you try to understand how React works by looking at this example you can easily get confused. Because Context is an advanced concept (at least for the beginners). Also, the code uses useReducer with Context and this makes the things more complicated. If your intent is to understand the React itself then start with the beginner guide .

By using Context we can pass the data top-down to the deepest components. But, in order to use that data those components should be rendered as children of the context provider.

In your code, you are doing this in ContactState but you never use it. Also, in that component, you are defining a state with useReducer and feed your context with this state by value .

Finally, in your ContactForm component, you are using useContext hook to get the context data. In your current code since you don't render this component in a provider, contactContext is undefined and you are getting the error. You can't get addContact from undefined.

In my example, I'm retrieving the contacts to show something. Again, I've changed/removed some parts from your code.

 const { createContext, useContext, useReducer } = React; const ContactContext = createContext(); function ContactForm() { // Changed those values const name = ""; const email = ""; const contactContext = useContext(ContactContext); // changed addContact -> contacts const { contacts } = contactContext; const onSubmit = () => { addContact(name.value, email.value); name.onReset(); email.onReset(); }; // added some data to render return <div>{contacts[0].name}</div>; } function ContactReducer(state, action) { switch (action.type) { case "ADD_CONTACT": return { contacts: [...state, action.payload] }; case "DEL_CONTACT": return { contacts: state.contacts.filter( contact => contact.id !== action.payload ) }; case "START": return { loading: true }; case "COMPLETE": return { loading: false }; default: throw new Error(); } } const ContactState = props => { const initialState = { contacts: [ { id: "098", name: "Diana Prince", email: "diana@us.army.mil" } ], loading: false, error: null }; const [state, dispatch] = useReducer(ContactReducer, initialState); const { contacts, loading } = state; const addContact = (name, email) => { dispatch({ type: "ADD_CONTACT", // removed lodash part, added a static id payload: { id: 1, name, email } }); }; const delContact = id => { dispatch({ type: "DEL_CONTACT", payload: id }); }; return ( <ContactContext.Provider value={{ contacts, loading, addContact, delContact }} > {props.children} </ContactContext.Provider> ); }; // added the relevant render part ReactDOM.render( <ContactState> <ContactForm /> </ContactState>, document.getElementById("root") ); 
 <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root" /> 

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