# react-music(hooks)
**Repository Path**: huangxiaolun/react-music-hooks
## Basic Information
- **Project Name**: react-music(hooks)
- **Description**: 用hooks构建的react项目,具有一定的参考性
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-02-23
- **Last Updated**: 2021-03-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
安装项目依赖:
```react
yarn install
```
项目运行:
```react
yarn start
```
知识点参考:coderwhy公众号 react知识点栏目
## 项目规范
**项目规范:项目中有一些开发规范和代码风格**
- 1.文件夹、文件名称统一小写、多个单词以连接符(-)连接;
- 2.JavaScript变量名称采用小驼峰标识,常量全部使用大写字母,组件采用大驼峰;
- 3.CSS采用普通CSS和styled-component结合来编写(全局采用普通CSS、局部采用styled-component);
- 4.整个项目不再使用class组件,统一使用函数式组件,并且全面使用Hooks;
- 5.所有的函数式组件,为了避免不必要的渲染,全部使用memo进行包裹;
- 6.组件内部的状态,使用useState、useReducer;业务数据全部放在redux中管理;
- 7.函数组件内部基本按照如下顺序编写代码:
- - 组件内部state管理;
- redux的hooks代码;
- 其他组件hooks代码;
- 其他逻辑代码;
- 返回JSX代码;
- 8.redux代码规范如下:
- - redux结合ImmutableJS
- 每个模块有自己独立的reducer,通过combineReducer进行合并;
- 异步请求代码使用redux-thunk,并且写在actionCreators中;
- redux直接采用redux hooks方式编写,不再使用connect;
- 9.网络请求采用axios
- - 对axios进行二次封装;
- 所有的模块请求会放到一个请求文件中单独管理;
- 10.项目使用AntDesign
- - 项目中某些AntDesign中的组件会被拿过来使用;
- 但是多部分组件还是自己进行编写;
- 其他规范在项目中根据实际情况决定和编写;
ps : js和jsx结尾一样 很多大型项目还是用js结尾
## 项目准备
### 文件夹
### css
```webpack
yarn add normalize.css -S
```
样式重置-*全局样式*
--如果要用到css变量(scss less)就需要在webpack里面去配置css了 -另一个项目有案例
### 配置别名-扩展webpack
```webpack
//想要修改webpack配置,但不使用yarn eject(也不推荐暴露)
yarn add @craco/craco
```


### 项目页面分析

> 构建解构
#### 配置路由
```route
yarn add react-router-dom
yarn add react-router-config //管理路由
```


## 知识点
> 问题一:采用什么css方式
传统方式:行内样式和类样式
react组件化开发,避免css污染 --解决办法:
1.**css-in-js** 在js文件中写css,样式文件的后缀名为 .js,这种方式最大的优点就是可以传递参数。(我不是很喜欢这种 因为js和css没有分离)
2.模块化样式,样式文件的后缀为.module.css,使用的时候以对象的形式来调用样式 (这种也太麻烦了)
3.利用sass或者less (就是在传统方式上,只不过我们要注意的是,就是每一个组件样式最外层需要一个 独一的样式名,这样就不会出现问题了啥)---**这是我比较能接受的**
```webpack
```
> classNames
动态切换样式,通过 classNames 插件来完成,通过对样式属性设置 true 或者 false,来设置是否将该样式应用到DOM对象中。
ps:原本这个项目用的css-in-js 样式 但是 我没有我通过scss方式来做
> 第一次配置还是有点麻烦



其它的直接引就是
## 二级路由

## 配置axios
```axios
/**axios封装
* 请求拦截、相应拦截、错误统一处理
*/
import axios from "axios";
// import { getToken, getSession } from "../utils/sesstion";
import { message } from "antd";
// import QS from "qs";
// 环境的切换--需要改
const BASEURL =
process.env.NODE_ENV === "production"
? process.env.REACT_APP_API
: process.env.REACT_APP_API;
axios.defaults.baseURL = BASEURL;
// 请求超时时间
axios.defaults.timeout = 15000;
// post请求头
axios.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded;charset=UTF-8";
// 请求拦截器
axios.interceptors.request.use(
(config) => {
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
// const token = getToken(),
// username = getSession("Username");
// token && (config.headers["Token"] = token);
// username && (config.headers["Username"] = username);
// config.headers.UserName = user.username
return config;
},
(error) => {
return Promise.error(error);
}
);
// 响应拦截器
axios.interceptors.response.use(
(response) => {
if (response.status === 200) {
// 在验证后端给的code
if (response.data.resCode !== 0) {
message.error(response.data.message);
return Promise.reject(response);
}
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是200的情况
(error) => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
// router.replace({
// path: '/login',
// query: { redirect: router.currentRoute.fullPath }
// });
break;
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
message.error("登录过期,请重新登录");
// Toast({
// message: '登录过期,请重新登录',
// duration: 1000,
// forbidClick: true
// });
// // 清除token
// localStorage.removeItem('token');
// store.commit('loginSuccess', null);
// // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
// setTimeout(() => {
// router.replace({
// path: '/login',
// query: {
// redirect: router.currentRoute.fullPath
// }
// });
// }, 1000);
break;
// 404请求不存在
case 404:
message.error("网络请求不存在");
// Toast({
// message: '网络请求不存在',
// duration: 1500,
// forbidClick: true
// });
break;
// 其他错误,直接抛出错误提示
default:
message.error(error.response.data.message);
// Toast({
// message: error.response.data.message,
// duration: 1500,
// forbidClick: true
// });
}
return Promise.reject(error.response);
}
}
);
/**
* get方法,对应get请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
function get(url, params = {}) {
return new Promise((resolve, reject) => {
axios
.get(url, {
params: params,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err.data);
});
});
}
/**
* post方法,对应post请求
* @param {String} url [请求的url地址]
* @param {Object} params [请求时携带的参数]
*/
function post(url, params = {}) {
return new Promise((resolve, reject) => {
// QS.stringify(params) -->这里邮箱@ 变成了百分号
axios
.post(url, params)
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err.data);
});
});
}
export { get, post };
```
## redux react-redux
就是这一套:配置还是不变


```react
//app.js
import { Provider } from "react-redux";
import store from "store";