生命周期
1 挂载阶段
1 constructor() --> 组件的创建到销毁, 只执行一次
1 它是class组件类的构造器, 当组件实例化时首先被调用
2 是所有生命周期中, 第一个执行的
3 内部用于定义, class类组件的变量, 且不可以使用this.setState()方法
2 render() ---> 组件的创建到销毁, 可执行多次
1 是所有生命周期中, 唯一的必须存在的生命周期
2 用于定义 class类组件视图的, 必须有 return 返回值, 且返回 JSX 元素对象
3 return 之前用于做业务逻辑, 该函数中不可使用 this.setState()方法
4 在装载阶段和更新阶段都会执行
5 书写的时候, 往往放在当前组件的最后面
3 componentDidMount() --> 组件的创建到销毁, 只执行一次 --> 常用
1 相当于 Vue中的 mounted() 表示视图初始化渲染完成
2 我们经常在此处 -- 触发调接口, 开启定时器, 长链接, DOM操作
2 更新阶段
1 componentDidUpdate() --> 不常用
1 相当于是 Vue中的 updated(), 它表示视图更新已完成
2 此处也不能使用 this.setState()
3 主要作用就是, 性能优化, 抽离处不参与视图渲染的变量, 让他们不执行diff运算
2 shouldComponentUpdate() --> 不常用
1 它是一个开关, 用于控制组件的更新
3 这个生命周期一定要返回一个布尔值, 返回 false时, 更新失败
3 卸载阶段
1 componentWillUnmount() --> 常用
1 相当于是 Vue中的 beforeDestroy()
2 在这里一般做清除定时器, 长连接, 清除状态管理的缓存
组合
1 组合在react中,是一种非常强大的组件复用的设计模式
2 本质上解决的是组件之间传值的问题, 它对于传值以及一些内部操控的逻辑封装得更严密
3 这种模式比较好的把复杂逻辑完全封装起来了, 比较适合开发组件的开发者
4 针对props的扩展性也比较好,对于使用组件的开发者来说,也比较友好
上下文
1 作用
1 Context 通过组件树提供了一个传递数据的方法, React.createContext()创建上下文
2 可以在 React组件树中进行数据传递, 避免使用复杂的链式的 props
3 上下文数据只能单向传递,从父组件向内部组件传递,不能倒着来
高阶组件
1 概念
--------------------------------------------------------------------------
1 高阶组件 == 高阶函数 == 容器组件 / 被其修饰的组件 == UI组件
2 作用说明
1 业务逻辑复用的高级技巧, 可让某一个组件, 通过高阶函数内部修饰, 实现功能扩展
2 高阶组件是非必须使用的, 宏观作用就是, 减少代码量, 让代码变得优雅简洁, 方便管理
3 理解
1 是基于React组件的组合特性而来一种设计模式
2 高阶组件就是一个函数, 接收组件, 基于这个类做一些扩展, return 一个新的组件出去
3 这个新的组件就包含了, 高阶函数内部的方法以及数据, 以及接收进来的组件实例
4 并且高阶函数内的新组件会向, 接收进来的组件实例, 以父子通信的方式传递需要的数据
5 也可以把高阶组件理解为一个工厂, 统一加工一些, 需要扩展某些相同功能的组件类
4 使用场景
1 若有 9个组件需要同一个接口数据, 可以把数据请求放在高阶函数内, 去帮需要的组件扩展
2 某些视图结构 (HTML结构), 需要被多个组件视图复用的情况
3 某些业务逻辑, 功能方法等, 需要在多个组件中复用的情况
3 注意
1 当一个UI组件同时被多个容器组件(高阶函数)修饰时, 发现 props有丢失的情况, 处理方案
1 以后写代码, 若需要被多个高阶组件修饰, 习惯性加这个展开运算符
2 高阶函数中, UI组件实例的位置: <A1 {
...this.props} />
2 class 类组件的装饰器语法, 知道就行了, 花里胡哨的不好用 --> @xx calss ...
----------------------------------------------------------------------------
4 高阶组件的 定义 + 使用
----------------------------------------------------------------------------
1 定义高阶函数 Test()
import React from 'react'
function Test(A1) {
return class extends React.Component {
constructor(props) {
super(props)
this.state = {
list: []
}
}
componentDidMount() {
const arr = [
{
id: 1, label: 'hehe1'},
{
id: 2, label: 'hehe2'},
{
id: 3, label: 'hehe3'}
]
this.setState({
list: arr})
}
render() {
return() {
<div> <A1 {
...this.props} hh="hehe" arrs={
list}/> </div>}}
}
}
export default Test
2 UI组件使用高阶函数 Test()的过程
import React from 'react'
import Test from '@/hoc/Test'
const A1 = props=> {
console.log(this.props)}
export default Test(A1)
----------------------------------------------------------------------------
HOOK
1 概念
1 从React 16.8 开始,增加 Hook 新特性
2 作用: 使用函数式组件, 也可以使用到生命周期, state 等特性
3 好处: 高性能的同时, 使用生命周期等特性
4 理解: HOOK 实际上就是一组 api,帮助你在函数式组件中, 使用React的固有特性
2 定义函数式组件的方式
1 function A1(props) {
return (<div> 呵呵</div>)}
2 const A2 = props => {
return (<div> 呵呵</div>)}
3 const A2 = props => (<div> 呵呵</div>)
----------------------------------------------------------------------------
3 函数式组件中使用 state --> useState()
----------------------------------------------------------------------------
1 按需引入
import React from 'react'
import {
useState} from 'react'
2 函数式组件中定义变量
export default props => {
1 使用API useState() , 定义一个声明式变量 msg1, 初始值为 1
2 同时定义一个 setMsg1方法, 专门用于修改声明式变量 msg1, 并且会触发 diff运算
const [msg1, setMsg1] = useState(1)
const [msg2, setMsg2] = useState([])
const [msg3, setMsg3] = useState(true)
3 定义组件方法 -- 注意不能修改变量本身的值, 可以是一个表达式结果 (setMsg1会修改)
function add() {
setMsg1(msg1+1)}
const sub = () => {
setMsg1(msg1-1)}
4 组件视图
return (
<div>
<h3> {
msg1} </h3>
<button onClick={
add}> +1 </button>
<button onClick={
sub}> -1 </button>
<button onClick={
()=>setMsg1(msg1+1)}> +1 </button>
</div>)
}
----------------------------------------------------------------------------
4 函数式组件中使用副作用 --> useEffect()
----------------------------------------------------------------------------
1 概念
1 副作用: 调接口, 定时器, DOM操作, 长连接等 逻辑都叫做副作用 (会影响组件性能)
2 通常这样的副作用, 写在生命周期函数里, 但是函数式组件中没有, this和生命周期函数
3 那么 useEffect API 就可以帮我们模拟出生命周期的特性, 然后就可以在函数式组件中执行副作用了
2 理解
1 在一个组件中可以使用多个副作用, (且当前副作用不会影响其他副作用)
2 通常一个副作用只做一件事, (避免代码相互干扰)
3 基础语法
1 ES6: useEffect(()=>{
return ()=>{
}}, [])
2 ES5: useEffect(function() {
return function() {
}}, [])
3 操作流程
1 按需引入
import React from 'react'
import {
useState} from 'react'
2 使用 useEffect
export default props => {
const [msg1, setMsg1] = useState(1)
useEffect(()=> {
return ()=> {
}
}, [])
useEffect(()=>{
return ()=>{
}}, [msg1])
useEffect(()=>{
return undefined}, [])
return ()
}
React 路由
1 概念
----------------------------------------------------------------------------
1 React 路由特点都是组件化的
2 react-router 是基于上下文实现的
3 路由配置的流程
1 路由模式的选择
2 修改 url的操作接口 (可以后写)
3 配置路由映射关系 (就是路由和对应组件的匹配规则)
4
5
----------------------------------------------------------------------------
2 安装
----------------------------------------------------------------------------
1 React路由有3个库 -- react-router / react-router-dom / react-router-native
2 npm install react-router -S
3 npm install react-router-dom -S ( 建议安装这个, 其实安装上面的也可以)
----------------------------------------------------------------------------
3 路由模式的选择 (俩种)
----------------------------------------------------------------------------
1 let {
HashRouter, BrowserRouter} from 'react-router-dom'
2 哈希模式: <HashRouter> <div>呵呵</div> </HashRouter>
3 history 模式: <BrowserRouter> <div>呵呵</div> </BrowserRouter>
4 用引入的组件实例 HashRouter把, 把组件视图包起来, 该组件就有了路由的功能
----------------------------------------------------------------------------
4 改变url的方式 (俩种) + 基础路由匹配规则
----------------------------------------------------------------------------
1 声明式路由跳转 -- App.js
1 let {
HashRouter, NavLink, Link, Route, Redirect} from 'react-router-dom'
2 <HashRouter> 视图结构 </HashRouter>
3 视图结构中(定义 3个改变 url的标签)
1 <NavLink to='/jsx'> jsx学习 </NavLink>
2 <NavLink to='/props'> props学习 </NavLink>
3 <Link to='/hh'> hh</Link>
4 视图结构中(定义视图标签 Route)
1 import Jsx from '@/pages/Jsx'
2 import Props from '@/pages/Props'
3 <Route path='/jsx' component={
Jsx}/>
4 <Route path='/props' component={
Props}/>
5 类似 Vue中的视图标签, 但是这么写没有路由配置文件, 代码乱而多, 而且不方便管理
6 所以我们通常把, 相关数据定义在一个文件中, 然后通过遍历渲染的方式, 在 App.js中定义视图标签
2 编程式路由跳转
1 凡是被 <Route>元素直接包裹的组件, 它的 props都能拿到路由相关 API
2 由于一部分公共组件, 没有在 App.vue中被<Route>渲染和包裹, 所以没有路由相关 API
1 通过一个内置的高阶组件来扩展
1 import {
withRouter} from 'react-router-dom'
2 A1组件: export default withRouter(A1)
2 通过内置 API来实现 (推介)
1 import {
useHistory} from 'react-router-dom'
2 const A1 = ()=>{
const h = useHistory()
3 公共组件只用路由相关 API, 应该是二级路由的使用需求
----------------------------------------------------------------------------
5 标准的路由规则映射定义
----------------------------------------------------------------------------
1 创建路由配置文件 src/router/index.js (定义路由映射关系)
2 引入要配置路由的组件
1 import Jsx from '@/pages/Jsx'
2 import Props from '@/pages/Props'
3 设置路由配置文件
export default [
{
id: 1, path: '/jsx', text: '学习Jsx', component: Jsx},
{
id: 2, path: '/props', text: '学习Props', component: Props}]
4 App.js 中使用
1 import routes from '@/router/index.js'
2 定义渲染 NavLink的方法()
1 感觉导航栏自己按需添加比较科学, 没必要在此处渲染
2 类似 Vue中的 router-link, 通过改变 url, 来达到显示路由对应组件的效果
renderNavLinks() {
return(
routes.map(v =>(<NavLink key={
v.id} to={
v.path}>{
v.text}</NavLink>)) )}
3 定义渲染视图容器的方法
1 给所有配置了路由的组件视图, 定义一个对应的视图容器 <Route>
2 如果自己直接写也是可以的, ( 1级路由文件少的情况下)
3 因为没有 Vue中的默认视图, 所以配置路由的 1级组件都要, 有自己对应的视图容器才可以显示
renderRoutes() {
return(
routes.map(v=>(<Route key={
v.id} path={
v.path} component={
v.component}/>)}
4 使用路由
return (<div>
<nav>{
this.renderNavLinks()}</nav>
<div class="main">
{
this.renderRoutes()}
</div>
</div>)
5 如何实现重定向 Redirect
1 import {
Redirect, Switch} from 'react-router-dom'
2 基于上面的代码
<div class="main">
<Switch>
{
this.renderRoutes()}
<Redirect from='/*' to='/jsx' />
</Switch>
</div>
----------------------------------------------------------------------------
6 动态路由传参
----------------------------------------------------------------------------
1 路由映射表配置 --> path: 'jsx/:id' // 目标页面路由配置
2 路由传参 --> <span onClick={
()=>props.history.push('jsx'+id)}></span> // 起始页面
3 目标页面接收路由参数
1 props.match.params.id // 直接接收
2 import {
useParams} from 'react-router-dom' // 内置 API 接收
const id = useParams().id
----------------------------------------------------------------------------
7 代码分割 (路由懒加载)
----------------------------------------------------------------------------
1 理解
1 把所有的 js文件打包在一个 js文件中, 如果这个项目很大这么干是不可取的, 就要对代码进行分割
2 Vue 中叫做路由懒加载, 这里叫做代码分割, 也是按需加载
2 步骤
1 安装
1 npm i @babel/plugin-syntax-dynamic-import -D // 用于支持动态导入语法
2 npm i @babel/preset-react -D //
3 npm i @loadable/component -S // 用于动态导入组件
2 使用
1 import loadable from '@loadable/component'
2 const Jsx = loadable(()=>import('@/pages/Jsx')) // 懒加载的写法
3 const routes = [{
id: 1, path: '/jsx', text: 'jsx语法', component: 'Jsx'}]
4 export default routes
5 简写: export default []
----------------------------------------------------------------------------
Axios 调接口
1 安装: npm i axios -S
2 axios 的二次封装, 跟 Vue中是一样的
3 基于二次封装再封装一个 API 接口文件
4 再需要数据的页面, 引入对应接口 API, 在 useEffect() 中请求数据
5 基本上除了, 调接口的位置, 和数据的处理方式, 跟 Vue是差不太多的
UI组件库
1 Ant Design
1 安装: $ npm i antd -S
2 导入样式 main.js: import 'antd/dist/antd.css'
3 在单文件组件中: 复制代码使用即可
4 主题设置: React Day8
常用脚手架介绍
1 create-react-app
1 他是 react官方的一个脚手架, 也是最早出现的一个脚手架
2 这个脚手架里面的不少功能是需要自己配置的 (前提是把相关配置文件暴露出来)
3 其他脚手架, 默认配置应该会更全面一点
2 DvaJS
3 umi
4 自己创建
状态管理库 mobx (Vuex)
1 概念
----------------------------------------------------------------------------
1 作用: 全局组件之间的数据共享, 很方便的做缓存
2 理解: 由于框架一般都存在, 组件通信, 所以有时候, 全局状态管理也不是必须的
3 mobx: 是一个状态管理工具, 解决的问题就是组件之间数据共享, 以及缓存问题
4 安装: npm i mobx -S
----------------------------------------------------------------------------
2 开始使用
----------------------------------------------------------------------------
1 创建状态管理文件: src/store/index.js
import X1 from './modules/x1.js'
class A1 {
constructor( this.x1 = new X1())}
export default new A1()
2 创建状态模块: src/store/modules/x1.js(以及定义全局数据)
import {
observable,
action,
computed,
makeObservable,
makeAutoObservable
} from 'mobx'
export default class X1 {
constructor(
makeObservable(this, {
msg1: observable}))
msg1 = 'hello'
changMsg() {
this.msg1 = 'xx' 调接口等等}
get hh() {
}
}
----------------------------------------------------------------------------
3 mobx-react 库
1 作用: 把状态管理( mobx容器)和 react 联系起来
2 安装: npm i mobx-react -S
3 联系起来
1 import {
Provider} from 'mobx-react'
2 import store from '@/store/index.js'
3 <Provider s1={
store}></Provider> 把 App.js的视图结构包裹起来; 且被路由包裹(习惯)
----------------------------------------------------------------------------
4 在组件中使用 mobx 状态数据
----------------------------------------------------------------------------
1 import {
observer, inject} from 'mobx-react'
2 export default inject(s1)(observer(A1))
3 此时 props会多出来 store -- const {
x1} = props.store
4 直接使用: return (<div> {
x1.msg1} </div>)
----------------------------------------------------------------------------
5 理解
----------------------------------------------------------------------------
1 inject(store)(UI组件)
2 observer(UI组件)
3 在单文件组件中的 useEffect( music.getMusic(参数)) 中触发调接口
----------------------------------------------------------------------------