1 高阶组件
1 高阶组件的使用方式
const A = () => {}
export default Test(A)
@test
@user
@demo
class A extends React.Component{}
class A extends React.Component{}
export default test(user(demo(A)))
2 注意事项:
1 修饰符语法只能用于类组件
2 当一个组件要同时被多个高阶组件修饰时, 用修饰器语法就很便捷, 或者用常规的方式嵌套
3 当一个UI组件同时被多个高阶组件修饰时, 发现 props 有丢失的情况, 如下解决方案
高阶组件内UI组件实例时 +{...this.props}: <A1 {...this.props} />
2 HOOKS
1 简单描述:
1 概念: React 16.8 的新增特性, 可以让函数式组件使用 state 以及其他的 React 特性
2 本质: React 内置了一组 API
3 常用 API:
1 useState
2 useEffect
3 useContext
3 useState()
import React from 'react'
import {useState} from 'react'
export default props => {
const [msg1, setMsg1] = useState(1)
const [msg2, setMsg2] = useState([])
function add() {setMsg1(msg1+1)}
const sub = () => {setMsg1(msg-1)}
}
注意事项:
1 定义变量一定要有初始值
2 定义变量的同时, 定义一个 setMsg1方法, 专门用于修改声明式变量 msg1, 并且会触发 diff运算
4 useEffect()
1 简单描述
1 副作用: 调接口, 定时器, DOM操作, 长连接等 逻辑都叫做副作用 (会影响组件性能)
2 通常这样的副作用, 写在生命周期函数里, 但是函数式组件中没有, this和生命周期函数
3 那么 useEffect API 就可以帮我们模拟出生命周期的特性, 然后就可以在函数式组件中执行副作用了
2 代码范式:
import React from 'react'
import {useEffect} from 'react'
export default props => {
useEffect(()=> {
return ()=> {
}
},[])
}
3 注意事项:
1 默认要写 [], 不写会有问题
2 若要在某个变量改变的时候, 重新触发 useEffect, 这么写 [msg]
useEffect(()=>{return ()=>{}}, [msg1])
3 useEffect(()=>{return undefined}, [])
4 ES6: useEffect(()=>{return ()=>{}}, [])
5 ES5: useEffect(function() {return function() {}}, [])
6 把相关问题放在一个副作用里, 因为一个组件可以创建多个副作用
3 React 路由
### 有时间搞, 还不是很完善, 暂时不需要 --> 基于 UmiJS 的路由规则
1 概念
----------------------------------------------------------------------------
1 React 路由特点都是组件化的
2 react-router 是基于上下文实现的
3 路由配置的流程
1 路由模式的选择
2 修改 url的操作接口 (可以后写)
3 配置路由映射关系 (就是路由和对应组件的匹配规则)
----------------------------------------------------------------------------
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'
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 []
----------------------------------------------------------------------------
4 Axios 调接口
### 有时间搞, 暂时不需要 (有 Dva 的 model)
1 安装: npm i axios -S
2 axios 的二次封装, 跟 Vue中是一样的
3 基于二次封装再封装一个 API 接口文件
4 再需要数据的页面, 引入对应接口 API, 在 useEffect() 中请求数据
5 基本上除了, 调接口的位置, 和数据的处理方式, 跟 Vue是差不太多的 (一般使用 Redux)
5 Mobx
1 简单描述:
----------------------------------------------------------------------------
1 概念: 也是一个全局状态管理工具
2 作用: 可以让全局组件之间实现数据共享
3 理解: 虽然框架一般都有组件通信的功能, 但是全局状态管理工具, 可以更人性的操作数据
4 使用流程:
1 安装相关的包, 做一个环境
2 主要是基于俩个文件: 全局状态管理的配置文件(涉及到分包) + 单文件组件中如何去使用
----------------------------------------------------------------------------
2 环境配置
--------------------------------------------------------------------------------------
1 相关安装:
1 npm i mobx -S
2 npm i mobx-react -S
1 环境配置: App.js
import { Provider} from 'mobx-react'
import store from '@/store/index.js'
<Provider store1={store}></Provider>
-------------------------------------------------------------------------------------
3 开始使用:
-------------------------------------------------------------------------------------
1 创建状态管理文件: src/store/index.js
import X1 from './modules/x1.js'
class Store{
constructor() {
this.x1 = new X1()
}
}
export default new Store()
2 创建状态模块: src/store/modules/x1.js
import {
observable,
action,
computed,
makeObservable,
makeAutoObservable
} from 'mobx'
class X1{
constructor() {
makeAutoObservable(this)
makeObservable(this, {
msg: observable,
})
}
msg = "不再期待爱情"
hh() {console.log(this.msg)}
get hh() {}
}
export default X1
3 单文件组件中怎么使用 mobx呢:
import React from 'react'
import { observer, inject} from 'mobx-react'
const A1 = props => {
const msg = props.store1.msg
const {msg} = props.store1
return (<div> {msg} </div>)
}
export default inject(store1)(observer(A1))
-------------------------------------------------------------------------------------
Redux
1 简单描述:
---------------------------------------------------------------------------
1 概念: 也是一个全局状态管理工具
2 作用: 可以让全局组件之间实现数据共享
3 使用流程:
1 安装相关的包, 做一个环境
2 主要是基于俩个文件: 全局状态管理的配置文件(涉及到分包) + 单文件组件中如何去使用
4 相关知识:
1 redux 中也是单向数据流的
2 redux 中只支持 dispatch() 派发同步的 action, 而不能派发异步的
3 dispatch() 的参数只能是一个对象
4 react 的默认规范, 所有外部数据, 都因该是从 props 中进来的
5 关于解决 dispatch() 不能派发异步任务的处理方式: thunk 工具的作用
1 dispatch(fn)
2 dispatch(fn) 正常情况 fn不是对象就会报错, 有了 redux-thunk就不会报错了
3 这样设置了之后, 如果 fn 是函数, 就会先调用这个方法, 然后再判断
4 由于要在这个位置调接口, 为了便于管理和维护, 我们会把这些 fn 方法集合在一个文件中去使用
5 新建目录 src/
描述吧:
1 dispatch(fetch) 触发调接口时, 此时 fetch 不是普通对象, 处理插件 -- thunk
---------------------------------------------------------------------------
2 环境配置:
---------------------------------------------------------------------------
1 需要安装的包:
npm i redux -S
npm i react-redux -S
npm i redux-thunk -S
npm i axios -S
2 App.js 中
import {Provider} from 'react-redux'
import store from './store/index.js'
<Provider store1={store}></Provider>
3 插件工具 redux-thunk 的环境配置: src/store/index.js
import thunk from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunk))
---------------------------------------------------------------------------
3 基础使用方式:
---------------------------------------------------------------------------
1 创建状态管理文件: src/store/index.js 🔷
import {
createStore,
applyMiddleware,
combineReducers
} from 'redux'
import home from './modules/x1'
import thunk from 'redux-thunk'
const initState = {
msg1: 'hello redux'
}
function reducer(state=initState, action) {
let newState = JSON.parse(JSON.stringify(state))
switch (action.type) {
case 'add':
break;
case 'del':
break;
default:
}
return newState
}
const store = createStore(reducer, applyMiddleware(thunk))
export default store
2 单文件组件中怎么使用 Redux 全局状态呢 🔷
import React from 'react'
import {connect} from 'react-redux'
cnost A = props => {
console.log(props.msg1)
console.log(props.hh)
}
function fn1(store) {
return { msg1: store.msg1}
}
function fn2(dispatch) {
return { hh: ()=>dispatch({type: 'add', payload: 'hello 2021'})}
}
export default connect(fn1, fn2)(A)
3 单文件函数式组件中, 还有一种使用方式(推介), 基于 hooks 的API 🔷
import {
useDispatch,
useSelector
} from 'react-redux'
const A = props => {
const msg = useSelector(store=>store.msg1)
const dispatch = useDispatch()
}
const ck1 = () => {
dispatch({type: 'add', payload: 'hello 2021'})
}
export default A
---------------------------------------------------------------------------
4 React 中数据请求 API 的位置: src/
---------------------------------------------------------------------------
1 说白了就是在, 单文件组件中编写请求数据的请求代码, 再把结果数据派发到, Redux 中去执行业务操作
2 而且会把, 这些请求的代码, 放在一个文件中集中管理
3 而且调接口调用并没有发生在组件里面, 二十发生在 thunk 插件代码里面
function h1(xx) {
return function (dispatch) {
api1(xx).then(res=>{
dispatch({
type: 'add',
payload: res.hh
})
})
}
}
dispatch(h1)
暂时这么理解
---------------------------------------------------------------------------
4 标准的一个开发流程:
---------------------------------------------------------------------------
2 创建状态子模块: src/store/moedules/x1.js
---------------------------------------------------------------------------