Search code examples
reactjsreact-reduxonscroll

I am getting background color value undefined in useSelector variable in React Redux


I am working on Header onscroll functionality. When user scroll down then background white should apply and when user scroll up to 0 then background transparent colour should apply. I am sending two objects via dispatch actions and getting it through useSelector. But I get undefined in bg property in console. Please correct me what I am doing wrong here. Below is the code.

HEADER.JS

import React, { useEffect } from 'react';
import './header.css';
import { useDispatch, useSelector } from 'react-redux';
import { changeBG, fetchHeader } from '../../redux/actions/header/HeaderActions';

const Header = () => {
  const dispatch = useDispatch();
  const logo = useSelector((state) => state.headerReducer.hData.logo);
  const parentLinks = useSelector((state) => state.headerReducer.hData.parentLinks);
  const bgColor = useSelector((state) => state.headerReducer.bg);
  console.log(bgColor);

  useEffect(() => {
    getHeaderApi();

    window.addEventListener('scroll', changeNavBG);
    return () => {
      window.removeEventListener('scroll', changeNavBG);
    };
  }, []);

  const getHeaderApi = async () => {
    // const apikey = process.env.REACT_APP_API_KEY;
    // const response = await fetch(
    //   `https://api.json-generator.com/templates/jy5YJ7qSuzOt/data?access_token=${apikey}`
    // );
    const response = await fetch(`http://localhost:8000/homepage`);
    const data = await response.json();
    // console.log(data);
    dispatch(fetchHeader(data.header));
  };

  const changeNavBG = () => {
    if (window.scrollY.toFixed() > 0) {
      dispatch(changeBG({ bg: 'bg-white' }));
    } else {
      dispatch(changeBG({ bg: 'bg-transparent' }));
    }
  };

  return (
    <>
      <div className={`dvHeader ${bgColor}`}>
        <div className="container-lg">
          <div className="row align-items-center pt-1">
            <div className="col d-lg-none">
              <i className="fa-solid fa-bars"></i>
            </div>
            <div className="col col-lg-auto text-center text-lg-left">
              <img width={50} src={logo && logo.url} alt="" />
            </div>
            <div className="dvSlideMenu col-lg-auto px-0 px-lg-3">
              <button className="btn btn-black closeBtn d-lg-none">
                <i className="fa-solid fa-xmark"></i>
              </button>
              <ul className="dvMenu">
                {parentLinks &&
                  parentLinks.map((item) => {
                    const { id, link } = item;
                    return (
                      <li key={id}>
                        <a href="">{link}</a>
                      </li>
                    );
                  })}
              </ul>
            </div>
            <div className="col col-lg-auto ml-lg-auto text-right">
              <i className="fa-solid fa-cart-shopping"></i>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

export default Header;

HEADER ACTIONS

export const fetchHeader = (data) => {
  return {
    type: 'FETCH_HEADER',
    payload: data,
  };
};

export const changeBG = (bgColor) => {
  return {
    type: 'CHANGE_NAV_BG',
    payload: bgColor,
  };
};

HEADER REDUCER

const headeriState = {
  hData: {},
  bgc: { bg: 'bg-transparent' },
};

export const headerReducer = (state = headeriState, action) => {
  switch (action.type) {
    case 'FETCH_HEADER':
      return {
        ...state,
        hData: action.payload, //data update
      };
    case 'CHANGE_NAV_BG':
      return {
        ...state,
        bgc: action.payload, //data update
      };
    default:
      return state;
  }
};

INDEX.CSS

/*header bg class change on scroll*/
.bg-white {
  background-color: rgba(255, 255, 255, 90%);
}
.bg-transparent {
  background-color: rgba(0, 0, 0, 0);
}

Solution

  • It should probably look like this hence headeriState is the same as state

    const bgColor = useSelector((state) => state.bgc.bg);