Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

useReducer returns undefined

-Hello guys , I’ve encountered a problem which taken a lot time in research but I did not get a solution:

->here I have 2 separate components header.jsx(contains booking.com homepage clone) and hotel.jsx and I want to send a state containing search data from header to hotel using context and use reducer . I’ve declared a separate context file searchcontext.js ,exported the context and its provider , wrapped the app using the provider in index.js , and I’ve called the dispatch function in header.js in order to send the needed state , when I call useContext in hotel.js to get the state the console return undefined ,any help please 🙂

index.js

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import React from 'react';
import ReactDOM from 'react-dom/client';

import App from './App';
import { SearchContextProvider } from './context/searchcontext';


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode> 
    <SearchContextProvider> 
    <App />
    </SearchContextProvider>
  </React.StrictMode>
);

searchcontext.js

import { createContext, useReducer } from "react";

const INITIAL_STATE = {
  city: undefined,
  dates: [],
  options: {
    adult: undefined,
    children: undefined,
    room: undefined,
  },
};

export const SearchContext = createContext(INITIAL_STATE);

const searchReducer = (action, state) => {
  switch (action.type) {
    case "NEW_SEARCH":
      return action.payload;
    case "RESET_SEARCH":
      return INITIAL_STATE;
    default:
      return state;
  }
};

export const SearchContextProvider = ({ children }) => {
  
  const [state, dispatch] = useReducer(searchReducer, INITIAL_STATE);

  return (
    <SearchContext.Provider
      value={{
        city: state.city,
        dates: state.dates,
        options: state.options,
        dispatch,
      }}
    >
      {children}
    </SearchContext.Provider>
  );
};

header.jsx file

import "./header.css";
import { DateRange } from "react-date-range";
import { useContext, useState } from "react";
import "react-date-range/dist/styles.css"; // main css file
import "react-date-range/dist/theme/default.css"; // theme css file
import { format } from "date-fns";
import { useNavigate } from "react-router-dom";
import  {SearchContext}  from "../../context/searchcontext";
const Header = ({ type }) => {
  
  const [destination, setDestination] = useState("");
  
  const [openDate, setOpenDate] = useState(false);
 
  const [dates, setDates] = useState([
    {
      startDate: new Date(),
      endDate: new Date(),
      key: "selection",
    },
  ]);
  const [openOptions, setOpenOptions] = useState(false);
  const [options, setOptions] = useState({
    adult: 1,
    children: 0,
    room: 1,
  });

 
  const navigate = useNavigate();
  const handleOption = (name, operation) => {
    setOptions((prev) => {
      return {
        ...prev,
      
        [name]: operation === "i" ? options[name] + 1 : options[name] - 1,
        
      };
    });
  };

  const{dispatch}= useContext(SearchContext);
 
  const handleSearch = () => {
    dispatch({type:"NEW_SEARCH",payload:{destination,dates,options}});
    console.log(true)
    navigate("/hotels", { state: { destination, dates, options } });
  };
  return (
    <div className="header">
      <div className="headerContainer" >
           
            <div className="headerSearch">
              <div className="headerSearchItem">
               
                <input
                  type="text"
                  placeholder="where are you going?"
                  className="headerSearchInput"
                  onChange={(e) => setDestination(e.target.value)}
                />
              </div>

              <div className="headerSearchItem">
                <span
                  onClick={() => setOpenDate(!openDate)}
                  className="headerSearchText"
                >
                  {`${format(dates[0].startDate, "dd/MM/yyyy")} to ${format(
                    dates[0].endDate,
                    "dd/MM/yyyy"
                  )}`}
                </span>
                {openDate && (
                  <DateRange
                    editableDateInputs={true}
                    onChange={(item) => setDates([item.selection])}
                    moveRangeOnFirstSelection={false}
                    ranges={dates}
                    minDate={new Date()}
                    className="date"
                  />
                )}
                
              </div>

              <div className="headerSearchItem">
               
                <span
                  onClick={() => setOpenOptions(!openOptions)}
                  className="headerSearchText">
                  {`${options.adult}`} adult {`${options.children}`} children
                  {`${options.room}`} room
                </span>
                {openOptions && (
                  <div className="options">
                    <div className="option">
                      <span className="optionTitle">Adults</span>
                      <div className="optionCounter">
                        
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("adult", "d");
                          }}
                          disabled={options.adult <= 1}
                        >
                          -
                        </button>
                        <span>{options.adult}</span>
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("adult", "i");
                          }}
                        >
                          +
                        </button>
                      </div>
                    </div>
                    <div className="option">
                      <span className="optionTitle">Children</span>
                      <div className="optionCounter">
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("children", "d");
                          }}
                          disabled={options.children <= 0}
                        >
                          -
                        </button>
                        <span>{options.children}</span>
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("children", "i");
                          }}
                        >
                          +
                        </button>
                      </div>
                    </div>
                    <div className="option">
                      <span className="optionTitle">Rooms</span>
                      <div className="optionCounter">
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("room", "d");
                          }}
                          disabled={options.room <= 1}
                        >
                          -
                        </button>
                        <span>{options.room}</span>
                        <button
                          className="optionCounterButton"
                          onClick={() => {
                            handleOption("room", "i");
                          }}
                        >
                          +
                        </button>
                      </div>
                    </div>
                  </div>
                )}
              </div>

              <div className="headerSearchItem">
                <button className="headerBtn" onClick={handleSearch}>
                  Search
                </button>
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  );
};

export default Header;

hotel.jsx file

import "./hotel.css";
import { useState } from "react";
import { useContext } from "react";
import { SearchContext } from "../../context/searchcontext";

const Hotel = () => {
  const [sliderNumber, setSliderNumber] = useState(0);
  const [openSlider, setOpenSlider] = useState(false);
  
  //here where the problem encouters
  const {state}= useContext(SearchContext);
  console.log(state);//returns undefined

  return (
    <div style={{ margin: -8 }}>
        <div className="hotelItemContainer">
          <div className="hotelItemWrapper">
            <button className="hotelBookBtn"> Reserve or Book Now!</button>
            <h1 className="hotelTitle">lorem</h1>
            <span className="hotelSpecFeatures">
              You're eligible for a Genius discount! , to save at this property
              , all you have to do is sign in.
            </span>
            
          </div>
          
        </div>
      
    </div>
  );
};

export default Hotel;

>Solution :

In your hotel.js you are expecting a state property. However you have not been exposing one in your search context

searchcontext.js

Your context was not exposing a state

export const SearchContextProvider = ({ children }) => {
  
  const [state, dispatch] = useReducer(searchReducer, INITIAL_STATE);

  return (
    <SearchContext.Provider
      value={{
        city: state.city,
        dates: state.dates,
        options: state.options,
        state, // you forgot to add this
        dispatch,
      }}
    >
      {children}
    </SearchContext.Provider>
  );
};

alternatively don’t use the state property in hotel.js instead use the destructure values that are exposed in your context.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading