React18 项目 entire页面划分 entire-filter 全部-房间列表数据获取和管理是方式 redux中异步网络请求 蒙版和分页器

106 阅读4分钟

entire页面划分

image.png

entire-filter

实现效果: image.png

import PropTypes from "prop-types";
import React, { memo, useState } from "react";
import { FilterWrapper } from "./style";
import filterData from "@/assets/data/filter_data.json";
import classNames from "classnames";

const EntireFilter = memo((props) => {
  const [selectItems, setSelectItems] = useState([]);
  
  function itemClickHandle(item) {
    const newItems = [...selectItems];
    if (selectItems.includes(item)) {//移除操作
      let selectIndex = selectItems.findIndex((v) => v === item);
      newItems.splice(selectIndex, 1);
    } else {//添加操作
      newItems.push(item);
    }
    setSelectItems(newItems);
  }
  return (
    <FilterWrapper>
      <div className="filter">
        {filterData.map((item, index) => {
          return (
            <div
              onClick={(e) => itemClickHandle(item)}
              className={classNames("itme", { active: selectItems.includes(item) })}
              key={item}
            >
              {item}
            </div>
          );
        })}
      </div>
    </FilterWrapper>
  );
});
EntireFilter.propTypes = {};
export default EntireFilter;
import styled from "styled-components";

export const FilterWrapper = styled.div`
  position: fixed;
  z-index: 99;
  left: 0;
  right: 0;
  top: 80px;

  display: flex;
  align-items: center;
  height: 48px;
  padding-left: 16px;
  border-bottom: 1px solid #f2f2f2;
  background-color: #fff;

  .filter {
    display: flex;
    .itme {
      margin: 0 4px 0 8px;
      padding: 6px 12px;
      border: 1px solid #dce0e0;
      border-radius: 4px;
      color: #484848;
      cursor: pointer;

      &.active {
        background: #008489;
        border: 1px solid #008489;
        color: #ffffff;
      }
    }
  }
`;

全部-房间列表数据获取和管理是方式

  • redux

image.png

export const CHANGE_CURRENT_PAGE = "entire/change_current_page";
export const CHANGE_ROOM_LIST = "entire/change_room_list";
export const CHANGE_TOTAL_COUNT = "entire/change_total_count";
import * as actionTypes from "./constants";
const initialState = {
  currentPage: 0, //当前页码
  roomList: [], //房间列表
  totalCount: 0, //总数居个数
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_CURRENT_PAGE:
      return { ...state, currentPage: action.currentPage };
    case actionTypes.CHANGE_ROOM_LIST:
      return { ...state, roomList: action.roomList };
    case actionTypes.CHANGE_TOTAL_COUNT:
      return { ...state, totalCount: action.totalCount };
    default:
      return state;
  }
}
export default reducer;
import * as actionTypes from "./constants";

export const changeCurrentPageAction = (currentPage) => ({
  type: actionTypes.CHANGE_CURRENT_PAGE,
  currentPage,
});

export const changeRoomListAction = (roomList) => ({
  type: actionTypes.CHANGE_ROOM_LIST,
  roomList,
});

export const changeTotalCountAction = (totalCount) => ({
  type: actionTypes.CHANGE_TOTAL_COUNT,
  totalCount,
});

统一导出

import reducer from "./reducer";
export default reducer;

放在store中:

import { configureStore } from "@reduxjs/toolkit";
import homeReducer from "./modules/home";
import entireReducer from "./modules/entire";
const store = configureStore({
  reducer: {
    home: homeReducer,
    entire: entireReducer,
  },
});
export default store;

组件中派发action

import React, { memo, useEffect } from "react";
import { EntireWrapper } from "./style";
import EntireFilter from "./c-cpns/entire-filter";
import EntireRooms from "./c-cpns/entire-rooms";
import EntirePagination from "./c-cpns/entire-pagination";
import { useDispatch } from "react-redux";
import { fetchRoomListAction } from "@/store/modules/entire/createActions";

const Entire = memo(() => {
  // 发送网络请求,获取数据,并且保存当前的页面...
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchRoomListAction());
  });
  return (
    <EntireWrapper>
      <EntireFilter />
      <EntireRooms />
      <EntirePagination />
    </EntireWrapper>
  );
});
export default Entire;

redux中异步网络请求

// 异步
export const fetchRoomListAction = () => {
  // 新的函数
  return async (dispatch, getState) => {
    // 1.根据页码获取最新的数据
    const currentPage = getState().entire.currentPage;
    // 网络请求
    const res = await getEntireRoomList(currentPage * 20); //偏移量 = 当前页 * 每页大小

    // 2.获取到最新的数据,保存在redux的store中
    const roomList = res.list;
    const totalCount = res.totalCount;
    // 派发action
    dispatch(changeRoomListAction(roomList));
    dispatch(changeTotalCountAction(totalCount));
  };
};

store -> modules -> entire -> createActions.js 全部代码:

import { getEntireRoomList } from "@/services/modules/entire";
import * as actionTypes from "./constants";

export const changeCurrentPageAction = (currentPage) => ({
  type: actionTypes.CHANGE_CURRENT_PAGE,
  currentPage,
});

export const changeRoomListAction = (roomList) => ({
  type: actionTypes.CHANGE_ROOM_LIST,
  roomList,
});

export const changeTotalCountAction = (totalCount) => ({
  type: actionTypes.CHANGE_TOTAL_COUNT,
  totalCount,
});

// 异步
export const fetchRoomListAction = () => {
  // 新的函数
  return async (dispatch, getState) => {
    // 1.根据页码获取最新的数据
    const currentPage = getState().entire.currentPage;
    // 网络请求
    const res = await getEntireRoomList(currentPage * 20); //偏移量 = 当前页 * 每页大小

    // 2.获取到最新的数据,保存在redux的store中
    const roomList = res.list;
    const totalCount = res.totalCount;
    // 派发action
    dispatch(changeRoomListAction(roomList));
    dispatch(changeTotalCountAction(totalCount));
  };
};

logo点击跳转到home页

import React, { memo } from "react";
import { LeftWrapper } from "./style";
import logo from "@/assets/img/logo.png";
import { useNavigate } from "react-router-dom";
const HeaderLeft = memo(() => {
  const navigate = useNavigate();
  function logoClickHandle() {
    navigate("/home");
  }
  return (
    <LeftWrapper>
      <img onClick={logoClickHandle} className="logo" alt="logo" src={logo} />
    </LeftWrapper>
  );
});
export default HeaderLeft;

蒙版和分页器

import PropTypes from "prop-types";
import React, { memo } from "react";
import { RoomsWrapper } from "./style";
import { shallowEqual, useSelector } from "react-redux";
import RoomItem from "@/components/room-item";

const EntireRooms = memo((props) => {
  // 从redux中获取数据
  const { roomList, totalCount, isLoading } = useSelector(
    (state) => ({
      roomList: state.entire.roomList,
      totalCount: state.entire.totalCount,
      isLoading: state.entire.isLoading,
    }),
    shallowEqual
  );
  return (
    <RoomsWrapper>
      <div className="title">{totalCount}多处住所</div>
      <div className="list">
        {roomList.map((item) => {
          return <RoomItem itemData={item} itemWidth="20%" key={item._id} />;
        })}
      </div>
      {/* 蒙层 */}
      {isLoading && <div className="cover"></div>}
    </RoomsWrapper>
  );
});
EntireRooms.propTypes = {};
export default EntireRooms;
import styled from "styled-components";

export const RoomsWrapper = styled.div`
  padding: 40px 20px;
  position: relative;
  .title {
    font-size: 22px;
    font-weight: 700;
    color: #222;
    margin: 30px 0 10px 10px;
  }

  .list {
    display: flex;
    flex-wrap: wrap;
  }

  /* 蒙层 */
  > .cover {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(255, 255, 255, 0.8);
  }
`;

isLoading 控制显示隐藏:

import * as actionTypes from "./constants";
const initialState = {
  currentPage: 0, //当前页码
  roomList: [], //房间列表
  totalCount: 0, //总数居个数
  isLoading: false,
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_CURRENT_PAGE:
      return { ...state, currentPage: action.currentPage };
    case actionTypes.CHANGE_ROOM_LIST:
      return { ...state, roomList: action.roomList };
    case actionTypes.CHANGE_TOTAL_COUNT:
      return { ...state, totalCount: action.totalCount };
    case actionTypes.CHANGE_IS_LOADING:
      return { ...state, isLoading: action.isLoading };
    default:
      return state;
  }
}
export default reducer;

网络请求前后切换状态:

dispatch(changeIsLoadingAction(true)); // 网络请求 
const res = await getEntireRoomList(currentPage * 20); //偏移量 = 当前页 * 每页大小 
dispatch(changeIsLoadingAction(false));
import { getEntireRoomList } from "@/services/modules/entire";
import * as actionTypes from "./constants";

export const changeCurrentPageAction = (currentPage) => ({
  type: actionTypes.CHANGE_CURRENT_PAGE,
  currentPage,
});

export const changeRoomListAction = (roomList) => ({
  type: actionTypes.CHANGE_ROOM_LIST,
  roomList,
});

export const changeTotalCountAction = (totalCount) => ({
  type: actionTypes.CHANGE_TOTAL_COUNT,
  totalCount,
});

export const changeIsLoadingAction = (isLoading) => ({
  type: actionTypes.CHANGE_IS_LOADING,
  isLoading,
});

// 异步
export const fetchRoomListAction = () => {
  // 新的函数
  return async (dispatch, getState) => {
    // 1.根据页码获取最新的数据
    const currentPage = getState().entire.currentPage;

    dispatch(changeIsLoadingAction(true));
    // 网络请求
    const res = await getEntireRoomList(currentPage * 20); //偏移量 = 当前页 * 每页大小
    dispatch(changeIsLoadingAction(false));

    // 2.获取到最新的数据,保存在redux的store中
    const roomList = res.list;
    const totalCount = res.totalCount;
    // 派发action
    dispatch(changeRoomListAction(roomList));
    dispatch(changeTotalCountAction(totalCount));
  };
};

分页

import React, { memo } from "react";
import { PaginationWrapper } from "./style";
import Pagination from "@mui/material/Pagination";
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import { fetchRoomListAction } from "@/store/modules/entire/createActions";
import { changeCurrentPageAction } from "@/store/modules/entire/createActions";

const EntirePagination = memo((props) => {
  const { totalCount } = useSelector(
    (state) => ({
      totalCount: state.entire.totalCount,
    }),
    shallowEqual
  );
  const dispatch = useDispatch();
  const totalPage = Math.ceil(totalCount / 20);
  function clickHandle(e, page) {
    dispatch(changeCurrentPageAction(page));
    dispatch(fetchRoomListAction());
  }

  return (
    <PaginationWrapper>
      <Pagination onChange={clickHandle} count={totalPage} color="secondary" />
    </PaginationWrapper>
  );
});
export default EntirePagination;
import styled from "styled-components";
export const PaginationWrapper = styled.div`
  display: flex;
  justify-content: center;
`;

分页效果:

image.png