react
什么是 react
专注视图层的响应式框架,单向数据流(数据从上往下走),单向数据绑定。
react,vue,jQuery 对比
- react:单向数据绑定,专注视图层
- vue:数据驱动视图,响应式框架
- jq:操作 dom 的类库
react 为什么必须使用 setState 修改呢?
单向数据绑定特性,必须使用 setState 函数修改,才能使组件进入更新阶段。
setState 默认是异步还是同步?如何成为同步?
异步,传入两个回调函数即可。
组件类型
类组件,函数组件(无状态组件)(hook 组件)
什么是高阶组件
- 定义:一个函数接收一个组件,返回一个类组件。
- 意义:为了复用组件里的方法逻辑等。【没有 hook 前,函数组件没有 react 的特性,所以才有了这种模式。】
生命周期
挂载阶段
- constructor
- render
- componentDidMount
更新阶段
- static getDerivedStateFromProps 可以对 props 和 state 进行再次修改的
- shouldComponentUpdate 是否要更新 true 更/false 否
- render
- componentDidUpdate
卸载
- componentWillUnmount
- componentDidCatch(err, info) {} 获取子组件错误的函数
性能优化
- shouldComponentUpdate 是否阻止组件更新
- memo
- useMemo
- useCallback
- pureComponent 等价于自动调用了 shouldComponentUpdate
- React.lazy 组件的按需加载
上下文对象
React.createContext 创建一个全局的共享上下文对象
父组件使用 context.Provider 提供共享数据
子组件 context.Consumer 接收共享数据且 Consumer 组件里必须用函数接收
// 全局上下文
const context = React.createContext();
// 父组件
<context.Provider value={data}>
<Son />
</context.Provider>;
// 子组件
<context.Consumer>{(data) => <div>{...data}</div>}</context.Consumer>;
懒加载组件
const Con = React.lazy(() => import("path/Con"));
<React.Suspense fallback="123123">
<Con />
</React.Suspense>;
hook
是 react 自 16.8 版本后新出的一套 api,其目的是为了让函数组件拥有全部的 react 特性。
const [list,setList]=useState([1,2,3])
- 赋值使用setList,不允许直接修改state,是用新值替换旧值的
hook 的生命周期
- 直接用:普通的更新钩子
- 空数组:挂载完成钩子
- 数组里有值:对该值进行监听,只有该值更新的时候才会触发,第一次监听值也会触发
- 返回一个函数:卸载,清除定时器
受控组件和非受控组件
- 受控组件:行为和交互被 react 控制的组件叫受控组件,比如:input 的 value 被 state 控制,赋值操作被 onChange 控制
- 非受控组件:不被 react 控制的,由用户自由操作。
eg:input 的 type 类型是 file
jsx
jsx 是类 xml 的一种格式,底层是 js;是 React.createElement()的语法糖
虚拟 dom 和 diff 算法
- 用 js 通过算法计算出来的 dom 对象,叫虚拟 dom。js 生成的。
- diff 算法:同层对比,发现不一致,就直接用新的 dom 替换旧的,且停止向下对比。
portals
让元素渲染到页面的任意节点下。
插槽
使用 Props.children 接受上游组件传入的子元素或内容
<Slot>老谢</Slot>
顶级 api
React.Component、React.PureComponent、React.createElement、React.cloneElement、React.children、React.Fragment、React.createContext、React.lazy、React.forwardRef、React.useState、React.useEffect、React.useRef、React.memo、React.useMemo、React.useCallback、ReactDOM.render、ReactDOM.createPortals、React.Suspense、React.createRef
细点
组件的布局
- React里 都不是正儿八经的原生的标签,是react虚拟dom,也就是对象,称为jsx语法;
- jsx语法就是React.createElement的语法糖
- React.createElement(),返回值就是一个虚拟dom的对象树,直接写在{表达式}里
- 背景图:直接写
- 前景图:
src={require('本地路径').default}
- 函数里只要返回的是dom元素,那么函数就叫做函数组件,官方里叫无状态组件
- {}是js表达式,专门用在虚拟dom里使用js内容的
组件的类别
函数组件–无状态组件–ui组件
- 好处:渲染快,代码简洁
- 缺点:纯函数组件缺失很多react特性,比如没有生命周期
- 适用于:写dom片段,所以又叫ui组件
类组件
- 很强大,也很笨重,也很不好理解
- 自定义的类组件需要继承于React里的类组件
- super:超级函数,初始化父级类的构造函数,并得到数据自己的this
- state:状态相当于vue里的data
- 第一个生命周期:constructor,相当于created;
- render:渲染函数,用于存放dom片段,相当于beforeMount
更新state
- 第一种:用setState,react里数据是单向绑定的,数据流也是单向的。只有调用了setState之后,才能让组件进入更新阶段,从而实现页面更新。
- 第二种:强制更新,forceUpdate(),但是会破坏生命周期
组建通信
- 父传子:子组件用props接收父组件传入的参数或者事件;
- 子传父:利用props传入回调函数。
状态和属性
state
- 状态,等价于vue的data
- react是单向数据流,单向数据绑定,不能直接修改state,setState()修改state
props
普通的虚拟dom叫属性,自定义属性叫传参
使用场景
- 父组件给子组件传属性 this.props.name
- {this.props.children},公共组件里个别内容,闭合组件里的子内容
<Child left={<Left title=""/>}/>
- 子组件调用父组件的方法
props和state相同点
- 都是纯js对象
- 都会触发render更新
- 都具有确定性
setState是否为异步?
- 是,在合成事件和生命周期里是异步的;在定时器里是同步的(setTimeout/setInterval,ajax,promise.then)
把异步的setState变成同步修改
- 传入两个回调函数,在第二个回调函数里获取新的state
事件
简易版防抖
- ajax 每输入一个字就请求一次,性能浪费了
- 解决方法:防抖–当用户结束交互之后一秒后再去执行,如果1秒内用户一直交互,我们就无限延时一秒钟
lodash节流防抖
- 初始化一个防抖函数:this.debounce=_.debounce(this.debounce,1000)
- 节流:this.debounce=_.throttle(this.debounce,1000)
- react里的on*事件都叫合成事件,底层做了修改,处理了浏览器兼容
- event对象也叫合成对象
- v16:合成对象在异步函数中会丢失属性值
Rcc
- currentTarget表示绑定的事件元素
- target表示触发事件的元素
PureComponent
- PureComponent在Component的基础上自动调用了shouldComponentUpdate函数,从而对props和state更新做了优化
- PureComponent默认优化了了组件更新,对比了更新时最新的props和旧的props值,如果两次一样,则使组件不更新
条件渲染
- 条件渲染 v-if v-show
- 循环渲染 map filter有返回值
- 表达式渲染 100/200*3+250
- 逻辑运算符:&& || !
- 判断运算符:=== !== > >= < <=
- 三目运算
- if switch 不能直接在dom里写,但是可以用
非受控组件
- type类型为file的input 典型的非受控组件,它的value数据是隐藏的二进制数据流,前端不能访问的,所以不能受控
- 可以给非受控组件加一个初始值
defaultValue=""
- 通过ref来获取非受控组件的内容
上下文对象
- 使用useContext安装上下文获取到最近的提供者组件的数据
- useContext 不受memo还有shouldComponentUpdate的优化
高阶组件
- hoc是个函数,里面返回一个类组件
- hoc函数,传入组件,得到一个类组件的实例对象,实例对象就是虚拟dom,用jsx语法渲染出来
- 高阶组件:一个函数接收一个组件,返回一个类组件
- HOC高阶组件:不是api,是一种策略模式
- 作用和目的:复用类组件的方法和事件
- 早期函数组件没有生命周期和状态,都是使用这种组合【策略】模式去实现复杂的组件开发
ref
三种绑定方式
- React.createRef()
- useRef()
- 回调函数
- 字符串[历史写法/;用于class组件]【已废弃】
- ref直接给类子组件使用,获取的是类组件的实例对象,如果给函数组件用则会报错
ref转发
- forwardRef((props,ref)
性能优化
- memo将组件包裹,自动去优化每一项props
- useMemo对传递进入子组件的属性进行优化
- 针对props进行优化:优化性能,对比本次数据和上一次是否一致,如果一样,则组件不更新
useReducer
- reducer是一个计算的函数
- 每次使用dispatch的时候,会触发reducer函数
reducer=(state,action)
state表示上一次的值,action是本地的动作