1

I have been trying to maintain my reducer in the same file as my Context provider. However, I have not been able to figure out how to consume it in a component file.

inside of my Context function:

const reducer = (state, action) => {
        switch (action.type) {
            case "SET_LOCATION":
                return {...state, location: action.payload}
            case "SET_BUSINESS":
                return {...state, business: action.payload}
            case "SET_DATE":
                return {...state, date: action.payload}
            default:
                return state
            }
    }

const [{location, business, date}, dispatch] = useReducer(reducer, {
        location: "",
        business: "",
        date: "today",
    })

return (
        <ThemeContext.Provider value={{location, business, date, dispatch, reducer}}>
            {props.children}
        </ThemeContext.Provider>
    )

at the component, inside of a form: I suspect I have not been using dispatch correctly, but couldn't figure out how to solve it by googling

const {location, business, date, dispatch, reducer} = useContext(ThemeContext)

     return (
              <form className="booking-form">
                <h1>Book a service</h1>
                <label>
                    Location
                <input 
                    type="text" 
                    name="location"
                    value={location} 
                    onChange={() => dispatch("SET_LOCATION")}    
                />
                </label>
                <br/>
                <br/>
                <label> 
                    Business
                <input 
                    type="text" 
                    name="business"
                    value={business}
                    onChange={() => dispatch("SET_BUSINESS")}
                />
                </label>
                    <h2 className="date">Date</h2>
                <label>
                <input 
                    type="radio"
                    name="date" 
                    value="today"
                    checked={date === "today"}
                    onChange={() => dispatch("SET_DATE")}
                />
                    Today
                </label>
                <label>
                <input 
                    type="radio"
                    name="date" 
                    value="tomorrow"
                    checked={date === "tomorrow"}
                    onChange={() => dispatch("SET_DATE")}
                />
                    Tomorrow
                </label>
                <label>
                <input 
                    type="radio"
                    name="date" 
                    value="other"
                    checked={date === "other"}
                    onChange={() => dispatch("SET_DATE")}
                />
                    Different date
                </label>
                {date === "other" ? <Calendar/> : <TimeGrid/>}
            </form>
skyboyer
  • 22,209
  • 7
  • 57
  • 64
uber
  • 4,163
  • 5
  • 26
  • 55

1 Answers1

0

Your reducer expects to receive an object with field type:

const reducer = (state, action) => {
  switch (action.type) {
  // we're checking field type here
  ...
}

But you're passing just string:

() => dispatch("SET_DATE")

You need to dispatch an action object with expected structure, since your reducer will receive an argument of dispatch() method as 2nd argument:

() => dispatch({ type: 'SET_DATE', payload: ... })

You also need to provide some payload since your reducer expect it:

const reducer = (state, action) => {
  return {...state, date: action.payload}
  // here we expect payload field on action object
}

One more improvement - please, extract your reducer from component, since it's kinda static pure function.

Andres
  • 967
  • 6
  • 7
  • what payload do I provide exactly? – uber Dec 05 '19 at 10:35
  • how to provide payload given that the input typed by the user is wanted? – uber Dec 05 '19 at 10:40
  • 1
    as a payload you need provide the value your reducer is using. For instance, for `SET_DATE` action you need to provide something to put in `date` field of your state. As i can understand from your code, you need to provide `"today"`, `"tomorrow"` or `"other"` string depending on radio button selected. For instance, for first radio you should do `dispatch({ type: 'SET_DATE', payload: 'today' })` – Andres Dec 05 '19 at 12:22