*高阶组件(HOC)
1.定义:高阶组件是参数为组件,返回值为新组件的函数
2.都用过哪些高阶组件:connect,withRoute
*setState是同步还是异步
setState 有同步也有异步
异步:react原生事件里的setState,写在生命周期里的setState
同步:原生js事件,setTimeout,setInterval,ajax
为什么是异步:如果是同步,比如我连续调用5次,页面就会刷新5次,浪费性能,所以把它做成异步的,对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖 取最后一次的执行结果,如果是同时setState多个不同的值,在更新时会对其进行合并批量更新
*memo:16.8 引入
*展示组件:公共组件 不包含 redux,dva 等具体状态,大部分参数是父组件传入
容器组件:父组件 包含 redux,dva 等状态,传递数据给展示组件
*Hook 使用
//useState
export default () => {
//异步
const [x1,setX1] = useState(1)
const [x2,setX2] = useState(() => {
//ajax
if(true){
return 3
}else{
return 2
}
})
const onClick = opt => {
//异步(等一小会)
setX1(x1 + 1)
//prevState 上一次的值
setX1(prevState => {
console.log(prevState,'prevState');
//return 出去的值就是x1的值
return prevState
})
console.log(x1,'x1');
}
return (
<div>
<h1>{x1}</h1>
<Button onClick={onClick}>改变x1</Button>
</div>
)
};
//useRef,createRef 区别
//1.createRef 只要组件重新渲染 createRef 就会重新执行
export default () => {
const [x1,setX1] = useState(() => {
return 1
})
//特性:useRef 页面渲染的时候只执行一次
//特性:只有current读写
//返回值:{current: undefined} 内存地址 abc
//作用1.获取DOM
//作用2.储存上一次的值
const ref = useRef()
const ref2 = createRef()
const onClick = opt => {
//ref.current === 1
ref.current = x1
ref2.current = x1
//异步
setX1(x1 + 1)
}
return (
<div>
<h1>{x1}</h1>
<h1 ref={ref}>小花</h1>
<h1 ref={ref2}>小蓝</h1>
<Button onClick={onClick}>改变x1</Button>
</div>
)
}
/*
用途:父组件刷新 子组件不刷新
返回一个新函数 如果依赖是空 新函数的指针永远不变
依赖是空 useCallback 永远只执行一次
const fn = useCallback(() => {
//如果依赖变了 重新返回指针变了的新函数
const fn = useCallback(() => {
},[x])
*/
export default function UseCallback() {
const [x,setX] = useState(0)
//console.log('我是父组件,我执行了');
//fn保存的123指针 -> () => console.log(1)
//第一次渲染 fn 123
//第二次 直接把123指针 给 fn
//第三次 直接把123指针 给 fn
const fn = useCallback(() => {
//console.log(1)
},[])
return (
<>
<h1 onClick={() => setX(x + 1)}>x:{x}</h1>
<QusecallBack
fn={fn} //123
/>
</>
)
}
/*
特性:
1.有一个返回值 回调函数里return 的值
2.useMemo 立刻执行的
const fn = useMemo(() => {
return 123
return () => {
}
},[])
*/
export default connect(({loading}) => {
return {
loading: !!loading.effects['upload/fetch']
}
})(useCallback)
function UseCallback (props){
const {dispatch,loading} = props
const [forms] = Form.useForm()
const [fileList,setFileList] = useState([])
const [x,setX] = useState(20000)
const [y,setY] = useState(20000)
//第一次刷新 x === 20000
//第二次 x === 20001
const x1 = useMemo(() => {
console.log('我执行了');
let sum = 0
for(let i=0; i<x; i++){
sum += i
}
return sum
},[x])
return (
<div style = {{background:'#000'}}>
<h1>x:{x1}</h1>
<h1>y:{y}</h1>
<h1 onClick={()=>setX(x+1)}>x:{x}</h1>
<h1 onClick={()=>setY(y+1)}>y:{y}</h1>
</div>
)
}
*Fiber
React Fiber是react执行渲染时的一种新的调度策略 javaScript是单线程的 一旦组件开始更新,主线程就一直被React控制 这个时候如果再次执行交互操作 就会卡顿 页面首次渲染会创建一颗结构,一模一样的Fiber节点数 Fiber在update的时候,会从原来的Fiber clone出一个新的Fiber 俩个Fiber diff出的变化 在更新结束后会取代之前的,Fiber节点树 渲染过程采用切片的方式 每执行一会儿 就歇一会儿 如果有优先级更高的任务 就会先去执行,降低页面发生卡顿的可能性,Fiber分片优先级分同步 异步 NoWork sync async,Fiber 更新任务分成俩个阶段 调节阶段 和 交付阶段 调节阶段 找出要做的更新工作可以被打断 例如 setState,useState,交付阶段需要提交所有更新并渲染 被设置为不能打断(然后说一下协调的三种diff算法),fiber 是个链表,有child和sibing属性 指向一个子节点和相邻的兄弟节点 从而构成 fiber tree
*JSX
是一个包含type,props,children的对象
*class生命周期
(react 16.4 之前)
三个阶段:加载阶段 更新阶段 卸载阶段
加载阶段:
constructor
render
componentDidMount
更新阶段:
componentWillReceiveProps(props)
shouldComponentUpdate(nextProps,nextState):nextProps && this.props(旧的)
render
componentDidUpdate
卸载阶段:
componentWillUnmount
(react 16.4 之后)
三个阶段:加载阶段 更新阶段 卸载阶段
加载阶段:
constructor
//getDerivedStateFromProps:
//1.里面没有 this
//2.return 的值 是改变 state,如果你不想改变state 就返回return null
getDerivedStateFromProps(nextProps,state)
render
componentDidMount
更新阶段:
getDerivedStateFromProps(nextProps,state)
shouldComponentUpdate(nextProps,nextState)
render
getSnapshotBeforeUpdate(nextProps,prevState)
componentDidUpdate
卸载阶段:
componentWillUnmount
*PureComponent:优化子组件渲染,自动判断基础类型数据,引用类型数据根据指针是否变化判断子组件是否渲染
*redux 工作流程:
view -> action -> state -> 重新渲染视图
redux react-redux redux-actions redux-persist redux-promise redux-thunk
*虚拟DOM
虚拟DOM是一个对象,包含type表示节点类型,props属性,props下包含children属性,子节点又包含,type属性,props属性,children属性,js通过使用document.createElement,document.createTextNode,递归循环这个对象,创建DOM树,然后用这个DOM树和真实DOM进行比较,这颗DOM树叫做虚拟DOM,react diff算法有三种:1.最外层节点不同,重新渲染全部节点,最外层节点相同则不重新渲染全部节点,2.相同节点的属性不同,只渲染不同的属性,不重新渲染节点 3.key相同不重新渲染节点,key不同重新渲染该节点
*react18:主要更新的是Concurrent并发(高优先级[不能打断],低优先级[可以打断])
1.startTransition:startTransition(()=>{ }):不用isPending直接使用这个方法
2.const [isPending,startTransition] = useTransition:startTransition(() => {})
3.useDeferredValue(值):你不能改父组件 父组件传了一个值给子组件 在子组件里把这个值变成低优先级
4.useId():生成一个id
5.useInsertionEffect(() => {},[])//DOM变更前同步触发 主要用来加载css in js
6.ReactDOM.createRoot,root.render
7.<Suspense fallback = {<h1>loading...</h1>}>
*不使用 antd 封装 Modal 组件,使用 ReactDOM.createPortal 把 Modal 插入到 body 下面和 root 同级 (为什么要和root同级,如果不同级放在 root 内,在页面里某个 div 如果有 overflow:hidden,Modal 可能无法做全凭遮罩)
<Modal
open={open}//bool
title={title}//string
close={close}//bool
footer={footer}//按钮扩展
onOk
onCancel
onClose //完全关闭
chilren
className
width
height
遮罩
style
确定文字
取消文字
loading
>
</Modal>
*Context 旧的使用方式
<ThemeContext.Consumer>
{
value => {
//value 父组件注入的值
}
}
<ThemeContext.Consumer>
*多页面应用 单页面应用
1.单页面应用(SPA)
(1)只有一个html文件,通过切换路由展示不同页面
(2)页面局部刷新
(3)不利于SEO(SEO:搜索引擎的优化,让我们的网站在搜索的时候靠前)
(4)不需要重复加载 css js ,所以页面切换后渲染快
(5)可以使用hash 也可以使用history模式(history模式上线后,刷新浏览器后页面会找不到,所以需要配置nginx)
2.多页面应用
(1)多个html页面
(2)切换页面 整个页面全部重新加载 用户体验差
(3)SEO实现容易
*react 实现 keep-alive 缓存:react-activation
*react 16.8 之前事件代理 事件委托 注册在document.onClick
react 16.8 root