组件
组件的两种写法
Class组件
- 继承+构造函数
- 利用this存放数据与函数
- 利用render()方法渲染和html
函数式组件
- 没有生命周期,继承与构造函数
- 借助Hook
- return Jsx
组件传值
父传子,props
React.cloneElement()可以克隆一个子节点,并给它附带一些属性,因此当遇到要给一系列标签都附带同一属性的时候,可以封装一个Wrapper利用map给每个子元素都附加属性
子传父
-
事件触发回调
-
ref转发
- 父组件定义ref,并将ref传给子组件
- 子组件接受ref,并给它添加change,clear等方法,并转发给父组件
- 父组件调用子组件传来的方法
组件间共享信息 context & reducer
- 在store里,定义Reducer,接收state与action,通过判定action的不同type而返回不同内容,并创建公共状态容器
- 在app里接收userReducer函数,和store容器,再利用
userReducer方法返回更新userReducer的方法,并将通过createContext()的方法传递context给子组件 - 子组件通过useContext接收
组件设计
- 接口定义
- 类名前缀统一
- 避免行内样式
- 避免在js中直接引入样式文件
5.组件样式按需加载
常见API
Hooks
hook规则&原理
- 只能在最顶层使用hook
如果在条件判定内使用hook,当该条件为否时,其内部的hook将不被执行,从而破坏了hook调用的顺序,使得state与useState的顺序混乱
-
只能在React函数中调用Hook
- 在React函数组件中或自定义Hook中调用
- 自定义Hook必须以use开头
- Hook中的state是完全隔离的
function useUpdatedEffect(effect, deps) {
const firstRender = useRef(true);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
}
else {
return effect();
}
}, deps);
}
function Form() {
//...
useUpdatedEffect(function persistForm() {
localStorage.setItem( 'formData', name);
}, [name]) ;
// ...
}
- 过期闭包
- 无论通过setCount()将count增加到何值,useEffect中输出的始终是0
解决方法: 只要将useEffect的第二个参数,即依赖设为count,就不会出现闭包问题
hook API
-
setState()传入一个初始值,返回一个状态和set该状态的函数,通过调用该函数可以实现状态修改
-
useEffect()传入一个函数,和一个数组,数组是状态的数组,为依赖项,该函数在mount和依赖项被set的时候执行
有"副作用"的函数,要传入useEffect执行,副作用代表除了计算,还要做其他的事,如网络请求,更新dom等
- 不要在循环,条件,嵌套里面使用hook
用react开发web应用
-
当子组件的props没有发生,无需进行新一次渲染
useCallback():定义一个不会每次都被重新定义的函数useMemo: 不会每次都会重新计算的值
优化用户体验
加载中
- lazy()&Suspense
使用React.lazy()包裹路由,Suspence展示等待加载过程渲染的内容
错误执行
- ErrorBoundary
在代码执行错误的时候渲染降级ui
React的实现
React.createElement()第一个参数为标签名,第二个参数是其属性,第三个参数为其子元素
如何更新dom
每次发生更新,不会直接更新dom,而是会更新虚拟dom,而后执行diff算法,比较虚拟dom树和真实dom树的差异
每当一个组件发生改变,其都会递归的更新其所有子组件,重新渲染整个虚拟dom的子树,然后才更新dom, 这也是react所产生的性能问题
如何更高效的diff
状态管理库
要使两个关系相隔很远的组件共享一个状态,需要将状态放在根节点上,而太多的状态堆积在根节点上,会影响性能,因此利用状态管理库,可以将状态抽离到ui外部进行统一管理