React 介绍
- Facebook 开源的一个 JavaScript 库
- React 结合生态库构成一个 MV* 框架
- React 特点:
- 声明式编码 (只需要声明在哪里做什么,而无需关心如何实现,比如数组原型上的那些高阶函数。编程式实现:需要以具体代码表达在哪里做什么,如何实现,比如 for 循环之类的。)
- Component-Based (组件化编码)
- 高效 (高效的 DOM Diff 算法,最小化页面重绘)
- 单向数据流
- 生态介绍
- React-Router (Vue-Router)
- Redux (Vuex)
- Axios
- Babel
- Webpack
React 生命周期
- getDefaultProps
- getInitialState
- componentWillMount
- render (必须)
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate (<--- this.setState())
- componentWillUpdate (<--- this.forceUpdate())
- componentDidUpdate
- componentWillUnmount
import React, { Component } from 'react';
class Child extends Component {
// 以下生命周期按顺序执行
// 首次会执行 componentWillMount、render、componentDidMount
// mount 钩子只会在组件中调用一次,其他的调用多次
componentWillReceiveProps(newProps) {
console.log('will use newProps', newProps);
}
shouldComponentUpdate(newProps) {
// 接受新的 props,如果返回 false, 就不会再调用 render 生命周期了
console.log('should update', newProps);
return newProps.value === 3 ? false : true;
}
componentWillUpdate(newProps) {
console.log('will update', newProps);
}
componentWillMount() {
console.log('will mount');
}
render() {
console.log('render');
return (
<div>Child</div>
);
}
componentDidMount() {
console.log('did mount');
}
componentDidUpdate(oldProps) {
// 接收老的 props
// 比如父组件设置了 state 里面的值,这里的 oldProps 里面的值就是 state 之前的值
console.log('did update', oldProps);
}
}
export default Child;
项目依赖安装
- axios
- antd (使用的 less,可以修改属于自己的主题,之所以我们可以引入 antd.css,是因为 less 文件已经被编译打包了,但是 antd 其实是采用 less 的方式来编写样式的!)
- react-router-dom
- redux
- less (安装less)
- less-loader (需要暴露出 webpack 配置: yarn eject)
- babel-plugin-import (按需加载组件代码和样式,比如我们引入了一个 Button 组件,那么相应的也只会引入 Button 的样式文件)
配置 less
// 暴露出 webpack 配置,编辑 webpack.config.js
// 编辑完之后重启服务即可
// 记住:use 采用从后到前来进行解析,loader 不要写反了
{
test: /\.less$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1
}
}, {
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require.resolve('postcss-flexbugs-fixes')
]
}
}, {
loader: require.resolve('less-loader')
}
]
},
配置按需加载 (安装 babel-plugin-import)
// 打开 webpack.config.js 文件
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
// 添加如下配置即可
// 项目打包就只会打包你引入了的组件和样式
plugins: [
['import', {
libraryName: "antd",
// 如果指定是 "css", 那么它就会引入 "antd/lib/button/style/css"
// 不过,你修改按钮的主题色的时候,就无法修改了,因为我们修改主题是通过改变 less 变量
// 而 css 文件是已经编译打包好了的
// style: "css"
// 指定为 true,它就会加载 "antd/lib/button/style"下的 less 模块
// 并将所有 less 模块进行动态编译成 css 文件
style: true,
}]
},
},
修改 Antd 的主题色
{
loader: require.resolve('less-loader'),
options: {
modules: false,
modifyVars: {
// 修改 antd 的主题色
"@primary-color": "#f9c700"
}
}
}
项目路由配置
- 项目的首页与登录页是同一层级的路由,所以配置的时候需要提前想好
- 定义一个 router.js 文件,放置第一层级路由
- 通过 this.props.children 获取组件内部的路由配置
// router.js
<Router>
<Route path='/login' component={Login} />
<Route path='/admin' render={(props) =>
<Admin>
<Route path={`${props.match.path}/home`} component={Home} />
<Route path={`${props.match.path}/ui/buttons`} component={Buttons} />
</Admin>
} />
</Router>
// Admin.js (用来对Home页面的一个布局)
class Admin extends Component {
render() {
return (
<Row className="container">
<Col span={4} className="nav-left">
<NavLeft />
</Col>
<Col span={20} className="main">
<Header />
<Row className="content">
// 渲染 Admin 组件内部的 Route
{this.props.children}
</Row>
<Footer />
</Col>
</Row>
);
}
}
Mock 数据以及接口请求封装
- easy mock (编写在线的接口)
- mock (配置需要接口返回的数据)
- axios (请求接口)
// 封装接口请求
import axios from 'axios';
import { Modal } from 'antd';
const baseURL = 'https://....';
class Axios {
static ajax(options) {
return new Promise((resolve. reject) => {
axios({
method: 'get',
url: options.url,
baseURL: baseURL,
timeout: 5000,
params: (options.data && options.data.params) || ''
}).then((response) => {
if (response.status === '200') {
const res = response.data;
if (res.code === 0) {
resolve(res);
} else {
// 接口数据报错
Modal.info({
title: '提示',
content: res.data.msg
});
}
} else {
// 接口报错
reject(response.data);
}
})
})
}
}
封装axios请求以及配置代理
使用 create-react-app 创建的项目可以直接在 package.json中配置 proxy
"proxy": "http://xx.x.x.xx:port", // 服务器地址
定制 axios
import axios from "axios";
import { Modal } from "antd";
const service = axios.create({
timeout: 10000
})
// 请求拦截
service.interceptors.request.use(config => {
console.log("config", config);
config.headers["Authorization"] = "token"; // 一般接口请求的话需要带上token
return config;
}, error => {
console.log("请求拦截error", error);
Promise.reject(error);
})
service.interceptors.response.use(response => {
let { data, statusText, status } = response;
return {
statusText,
status,
data: JSON.parse(data) // 如果后端返回的数据是json序列化之后的数据需要解析
}
}, error => {
Modal.warning({
title: error.response.status,
content: error.response.statusText
})
Promise.reject(error);
})
export default service;
如何请求 (可以封装请求方法,比如 get 请求)
import service from '../utils/request';
import { Modal } from 'antd';
export function ApiGet(url, params) {
return new Promise((resolve, reject) => {
service.get(url, params)
.then(res => {
if (res.status === 200) {
Modal.success({
title: res.status,
content: "请求成功!"
});
resolve(res);
} else {
Modal.warning({
title: res.status,
content: res.statusText
});
reject(res);
}
})
.catch(err => {
console.log("err", err)
Modal.warning({
title: "Error",
content: "请求错误!"
})
reject(err);
});
});
}
调用就很简单了
ApiGet("接口").then(res => {
console.log(res);
}, err => {
})