react项目创建(个人笔记)

react项目创建

个人纪录,有些杂乱(介意勿看)
主要包括配置别名、配置路由、使用 styled-components、axios 封装、redux管理数据、immutable的使用等
1、 目录结构
在这里插入图片描述

2、配置css

yarn add normalize.css

重置 css reset.css
3、配置别名

yarn add @craco/craco

修改package.json

` "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "react-scripts eject" },`

新建并配置 craco.config.js

const path = require("path");
const resolve = (dir) => path.resolve(__dirname, dir);

module.exports = {
  webpack: {
    alias: {
      "@": resolve("src"),
      components: resolve("src/components"),
    },
  },
};

4、安装路由

yarn add react-router-dom

统一管理路由 安装

 yarn add react-router-config

配置路由index

import Discover from "@/pages/discover";
import Friend from "@/pages/friend";
import Mine from "@/pages/mine";

const routes = [
  {
path: "/",
exact: true,
component: Discover,
  },
  {
path: "/mine",
component: Mine,
  },
  {
path: "/friend",
component: Friend,
  },
];
export default routes;

导航添加链接

import React, { memo } from "react";
import { NavLink } from "react-router-dom";

export default memo(function AppHeader() {
  return (
    <div>
      <NavLink to="/">发现音乐</NavLink>
      <NavLink to="/mine">我的音乐</NavLink>
      <NavLink to="/friend">我的朋友</NavLink>
    </div>
  );
});

APP.js使用renderRoutes

import React from "react";
import { renderRoutes } from "react-router-config";

import AppFooter from "@/components/app-footer";
import AppHeader from "@/components/app-header";
import routes from "@/router";
import { HashRouter } from "react-router-dom";

export default function App() {
  return (
    <HashRouter>
      <AppHeader />
       {/* 路由映射到的对应组件 */}
      {renderRoutes(routes)}
      <AppFooter />
    </HashRouter>
  );
}

使用 styled-components

yarn add styled-components

style.js

import styled from "styled-components";

export const HeaderWrapper = styled.div`
  height: 75px;
  font-size: 14px;
  color: #fff;
  background-color: #242424;
  position: relative;

  .content {
    height: 70px;

    display: flex;
    justify-content: space-between;
  }

  .divider {
    height: 5px;
    background-color: #c20c0c;
    width: 100%;
    position: absolute;
    left: 0;
    bottom: 0;
  }
`;

使用style创建的组件HeaderWrapper
在这里插入图片描述
使用ant-design及其图标

yarn add antd
yarn add @ant-design/icons

获取子路由对应的组件
子路由:routes里的routes
在这里插入图片描述
获取子路由对应的组件

import React, { memo } from "react";
import { renderRoutes } from "react-router-config";

import { dicoverMenu } from "@/common/local-data";

import { DiscoverWrapper, TopMenu } from "./style";
import { NavLink } from "react-router-dom";

export default memo(function Discover(props) {
  // 从props里拿到route对象,里面包含有子路由数组
  const { route } = props;
  console.log(route);
  return (
    <DiscoverWrapper>
      <div className="top">
        <TopMenu className="wrap-v1">
          {dicoverMenu.map((item, index) => {
            return (
              <div className="item" key={item.title}>
                <NavLink to={item.link}>{item.title}</NavLink>
              </div>
            );
          })}
        </TopMenu>
      </div>
      {/* 路由映射到的对应组件 */}
      {renderRoutes(route.routes)}
    </DiscoverWrapper>
  );
});

引入axios

yarn add axios

axios 封装
config.js
在这里插入图片描述

const devBaseUrl = "http://xxx";
const proBaseUrl = "http://xxx";
//判断当前环境是开发环境还是生产环境
export const BASE_URL =
  process.env.NODE_ENV === "development" ? devBaseUrl : proBaseUrl;
export const TIMEOUT = 5000;

request.js

import axios from "axios";

import { BASE_URL, TIMEOUT } from "./config";

//axios.create 能创造一个新的 axios 实例
const instance = axios.create({
  baseURL: BASE_URL,
  timeout: TIMEOUT,
});

// 请求和响应拦截
// 请求拦截
instance.interceptors.request.use(
  (config) => {
    // 1.发送网络请求时, 在界面的中间位置显示Loading的组件
    // 2.某一些请求要求用户必须携带token, 如果没有携带, 那么直接跳转到登录页面
    // 3.params/data序列化的操作
    //  console.log("请求被拦截");

    return config;
  },
  (err) => {}
);

instance.interceptors.response.use(
  (res) => {
    return res.data;
  },
  (err) => {
    if (err && err.response) {
      switch (err.response.status) {
        case 400:
          console.log("请求错误");
          break;
        case 401:
          console.log("未授权访问");
          break;
        default:
          console.log("其他错误信息");
      }
    }
    return err;
  }
);

export default instance;

页面使用:

import request from "@/services/request";

useEffect(() => {
    request({
      url: "/banner",
    }).then((res) => {
      console.log(res);
    });
    return () => {};
  }, []);

使用redux管理数据

yarn add redux react-redux redux-thunk

创建store(使用redux-thunk中间件)

import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";

const store = createStore(reducer, applyMiddleware(thunk));
export default store;

reducer(使用combineReducers )

import { combineReducers } from "redux";

import { reducer as recommendReducer } from "../pages/discover/c-pages/recommend/store";

const cReducer = combineReducers({
  recommend: recommendReducer,
});
export default cReducer;

App.js获得到共享的store

import { Provider } from 'react-redux'
import store from './store'

// 共享store
    <Provider store={store}>
      <HashRouter>
      <AppHeader />
      {/* 路由映射到的对应组件 */}
      {renderRoutes(routes)}
      <AppFooter />
    </HashRouter>
    </Provider>

使用创建的新的axios实例请求数据
在这里插入图片描述
推荐(recommend组件)单独创建一个sore文件夹,新建对应文件

1、actionCreators.js
在这里插入图片描述
2、constants.js

export const CHANGE_TOP_BANNERS = "recommend/CHANGE_TOP_BANNERS";

3.index.js
导出reducer

import reducer from "./reducer";

export { reducer };

reducer.js

import * as actionTypes from "./constants";

const defaultState = {
  topBanners: [],
};

function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_TOP_BANNERS:
      return { ...state, topBanners: action.topBanners };
    default:
      return state;
  }
}

export default reducer;

在recommend/index.js

import React, { memo, useEffect } from "react";
import { connect } from "react-redux";
import { getTopBannerAction } from "./store/actionCreators";

function Recommend(props) {
  const { getBanners, topBanners } = props;
  useEffect(() => {
    getBanners();
    return () => {};
  }, [getBanners]);

  return (
    <div>
      <h2>Recommend{topBanners.length}</h2>
    </div>
  );
}
const mapStateToProps = (state) => ({
  topBanners: state.recommend.topBanners,
});

const mapDispathToProps = (dispatch) => ({
  getBanners: () => {
    dispatch(getTopBannerAction());
  },
});

export default connect(mapStateToProps, mapDispathToProps)(memo(Recommend));

使用immutable.js和 redux hook

yarn add immutable

reducer.js

import { Map } from "immutable";
import * as actionTypes from "./constants";
//immutable  Map
const defaultState = Map({
  topBanners: [],
});

function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_TOP_BANNERS:
      return state.set("topBanners", action.topBanners);
    default:
      return state;
  }
}

export default reducer;

index.js

import React, { memo, useEffect } from "react";
//shallowEqual  useSelector的第二个参数,进行浅层比较
import { useSelector, useDispatch, shallowEqual } from "react-redux";
// import { connect } from "react-redux";
import { getTopBannerAction } from "./store/actionCreators";

function Recommend(props) {
  //使用hook redux
  //react hooks中使用useSelector获取存在redux中的状态
  //useSelector存在性能问题,需传入第二个参数shallowEqual进行浅层比较
  const { topBanners } = useSelector(
    (state) => ({
      // topBanners: state.recommend.topBanners,
      //使用immutable的Map中的get
      topBanners: state.recommend.get("topBanners"),
    }),
    shallowEqual
  );
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(getTopBannerAction());
  }, [dispatch]);

  return (
    <div>
      <h2>Recommend{topBanners.length}</h2>
    </div>
  );
}

export default memo(Recommend);

combineReducers中使用immutable

yarn add redux-immutable
import { combineReducers } from "redux-immutable";

import { reducer as recommendReducer } from "../pages/discover/c-pages/recommend/store";
import { reducer as playerReducer } from "../pages/player/store";

const cReducer = combineReducers({
  recommend: recommendReducer,
  player: playerReducer,
});
export default cReducer;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值