「ReactNaitve」对hooks最佳实践的探索
author: 轩邈
一、hooks介绍
一. useState
eg: const [count, setCount] = useState(0)
介绍
(1)有一个参数:默认值, 可以是函数,只在初始渲染时执行一次
(2)返回一个带有两个元素的数组
(3)第一个元素是 state 的值, 第二个元素是更新state的函数,每次新的,使用useCallback,可以让它使用上次的函数;函数名随意不一定是set某某某,参数可以是要更新的值或者函数,当是函数时,函数参数是上一次state的值。
(4) 如果有多个state则根据 useState 的调用顺序来“记住”每个state的状态归属 (5)这个特性要求Hooks不可以写在if或者switch等可能不执行的代码片段,会导致调用次序不一致
复制代码
二. useLayoutEffect
签名与 useEffect 相同,在DOM变化(layout布局)后同步触发,渲染之前(paint绘制)执行 ,适用于用户可见的 DOM 改变。
三. useEffect
与 componentDidMount
和 componentDidUpdate
不同,传递给 useEffect
的函数在DOM变化(layout布局) 和渲染(paint绘制)后触发。 这使得它适用于许多常见的 side effects ,例如设置订阅和事件处理程序,因为大多数类型的工作不应阻止浏览器更新(判断标准)屏幕。
1. eg:
`componentDidMount: useLayoutEffect(() => {setTitle(1)}, [])` `componentDidUpdate: useLayoutEffect(() => {console.log(1)})` `componentWillUnmount: useLayoutEffect()=>{return () => {console.log('我要卸载组件啦')}}` 我是一个方法,组件更新后返回,下次组件更新前执行:`useLayoutEffect(() => {return () => {console.log(‘我是一个方法,组件更新后返回,下次组件更新前执行')}}, [count, count2])`
复制代码
2. 介绍:相当于 componentDidMount 、 componentDidUpdate 、componentWillUnmount和 我是一个方法组件更新后返回,下次组件更新前执行
3. 有两个参数
1. 第一个为函数,默认会在渲染完成后执行一次,如果返回的是一个函数,则返回的函数会在第二个参数数组里面的元素发生变化且渲染完成后执行 2. 第二个为一个数组(也可以写成常量等类型,不过不会调用参数一),里面写需要监控的state,当state改变时会调用第一个函数,不改变则不会调用参数一,当数组为空时,只会在最开始调用一次,相当于componentDidMount;不传时,默认监控所有state,相当于componentDidUpdate
复制代码
四. useContext
1. eg:
const theme = useContext(ThemeContext)
复制代码
2. 使用 Contex时
```javascriptconst ThemeContext = React.createContext();const LanguageContext = React.createContext();``````js<ThemeContext.Consumer>{theme => (<LanguageContext.Cosumer>language => {//可以使用theme和lanugage了}</LanguageContext.Cosumer>)}</ThemeContext.Consumer>```两个render props写法,两个嵌套看起来麻烦很多使用useContext时 ```jsconst theme = useContext(ThemeContext);const language = useContext(LanguageContext);// 这里就可以用theme和language了```接受一个由React.createContext返回的上下文对象,写法简化很多并且不再需要理解render props
复制代码
3. 有时候会造成意想不到的重新渲染
```javascriptconst ThemedPage = () => {const theme = useContext(ThemeContext);return (<div><Header color={theme.color} /><Content color={theme.color}/><Footer color={theme.color}/></div>);};```当theme的其他属性(如size等其他非color属性)改变时也会导致界面重新渲染
复制代码
五. useReducer
1. 介绍:增强版的useState, 小型Redux (机制类似,但是不同组件内部数据认识独立的,)
2. eg:
```javascriptconst initialState = { count: 0 } const reducer = function reducer(state, action) { switch (action.type) { case 'reset': return initialState case 'increment': return { ...state, count: state.count + 1 } case 'decrement': return { ...state, count: state.count - 1 } default: return state }}```//上面这部分应该写在函数组件外面防止函数一遍遍的创建const [count3, count3Dispatch] = useReducer(reducer, initialState)
复制代码
3. 和useState相比dispatch和reducer只被创建了一次
六. useCallback
1. 介绍:返回值为 memoized 回调函数,第一个参数为一个函数,第二个为一个数组,只有内部元素变化,返回的回调函数才会被重新创建
2. eg:
```javascriptconst [count4, setCount4] = useState(0) const counterRef = useRef(count4) useEffect(() => { counterRef.current = count4 }, [count4] )const incrementCount4 = useCallback(() => setCount4(counterRef.current + 1), []) ```
复制代码
- 尽量少用,一般都能用useReducer优化
七. useMemo
介绍:useCallback(fn, inputs) 等价于 useMemo(() => fn, inputs)
八. useRef
介绍:useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数(initialValue)。返回的对象将存留在整个组件的生命周期中。
九. useImperativeMethods
- useImperativeMethods 自定义使用 ref 时公开给父组件的实例值,方便对函数式组件进行ref操作 使调用内部函数成为可能
- 应尽量避免这种代码
十. 自定义Hooks兴起可形成一种约定,代码之间的公用逻辑可以使用useXXX形式的函数
```javascript
// eg:
const useMountLog = name => {useEffect(() => {console.log(`${this.name}组件渲染时间->${this.end - this.begin}ms`)},[])
}
```
复制代码
// eg: usePrevious
function usePrevious(value) {const ref = useRef()useEffect(() => {ref.current = value})return ref.current
}
复制代码
二、环境构建
- git clone github.com/facebook/re… (我使用时react版本为16.6.1)
- cd react
- 将
packages/shared
目录下所有文件中的enableHooks = false
替换为enableHooks = true
- 运行
yarn install
- 运行
yarn build -- --type=RN_OSS
- 等运行完毕后,将
build/react-native/
下的内容替换项目路径/node_modules/react-native/Libraries/Renderer
(我使用时react-native版本为0.57.8)下的内容 - 项目中react版本为16.7.0-alpha.2(16.7.0-alpha.0~16.7.0-alpha.2皆可,16.7.0正式版将hooks移除了)
三、原有项目改造
替换类组件
// 改造前 export default class HomeScene extends Component{...} // 改造后 export default forwardRef((props, ref) => {...}) // forwardRef包起来是方便函数组件内部方法调用 复制代码
构造函数移除
state状态修改和创建改为useState
const [visible, setVisible] = useState(false)
改造前父组件通过ref引用子组件的方法,改造后使用
forwardRef
将createRef创建的ref传递到子组件内部,再使用useImperativeMethods将内部方法绑定到传进来的ref上useImperativeMethods(ref, () => ({ showModal: this.showModal }), []) 复制代码
方法
// 改造前 showModal = (from, data, ticket) => {...} // 改造后 this.showModal = (from, data, ticket) => {...} // 推荐使用箭头函数方便函数间调用 复制代码
render改为return,按state状态变化将原先render前的逻辑移入对应useEffect。
引入redux-react-hook
(1)引入StoreContext将根组件包起来
<StoreContext.Provider value={store}>... </StoreContext.Provider> 复制代码
(2)```javascript // 改造前 const { name, cityName } = this.props.UserInfo // 改造后 const mapState = React.useCallback(state => state.UserInfo, []) const { name, cityName } = useMappedState(mapState)
(3)每次调用useMappedState都会执行subscribe store。 但是,如果store更新,你的组件将只重新渲染一次。 因此,多次调用useMappedState(例如封装在自定义hooks中)不应该对性能产生很大影响。 如果测试发现性能影响较大,可以尝试返回对象。复制代码
引入react-navigation-hooks,需升级react-navigation至最新版(3.1.0)适配。
(1)使用
```javaScriptconst { navigate } = useNavigation()```与原先的路由管理共用一套路由
复制代码
(2)注意:
1) 如果项目是用pod管理,该RNGestureHandler.podspec里面路径有问题需要修改。2) createBottomTabNavigator的第二个参数BottomTabNavigatorConfig的navigationOptions属性改为了defaultNavigationOptions
复制代码
四、注意事项
- 原先的组件增强基础设施,如高阶组件和反向集成之类的组件需要进行相应修改以适应新的函数组件。
- forwarfRef需要额外关注,因为forwardRef包裹组件后返回的是React节点需要单独处理
target.$$typeof === Symbol.for('react.forward_ref')
(我暂时是这样处理的) - 需要注意增强组件的name或displayName设置,方便错误定位
- eslint-plugin-react-hooks: (1)在每个渲染上以相同的顺序调用 Hooks (不能在循环、判断、switch中使用)。 (2)对 Hooks 的调用要么在 PascalCase 函数内(假设是一个组件),要么是另一个 useSomething 函数(假定为自定义Hook)。
- 私以为hooks最大的亮点还是在于逻辑复用的易用性提升上,这个需要我们及时转变思路,习惯函数式组件开发。
- 如果inputs为[](useCallback的第二个参数),React每次渲染都将使用同样的函数返回值(不管里面的运算),这时你可以选择在函数组件外声明这个函数,但是React官方并不推荐这样做,hooks的重点就是是允许你保留组件中的所有内容。
- 我们对组件增强时,组件的回调一般不需要销毁监听,而且仅需监听一次,这与 DOM 监听不同,因此大部分场景,我们需要利用
useCallback
包裹,并传一个空数组,来保证永远只监听一次,而且不需要在组件销毁时注销这个 callback。 - hooks目前还有很多坑,是趋势,可了解,慎用。
原文链接: tech.meicai.cn/detail/81, 也可微信搜索小程序「美菜产品技术团队」,干货满满且每周更新,想学习技术的你不要错过哦。
「ReactNaitve」对hooks最佳实践的探索相关推荐
- 「C++」遗传算法求解最佳路径问题——“一日游”行程规划程序
「C++」遗传算法求解最佳路径问题--"一日游"行程规划程序 1 题目描述 2 题目要求 3 解决方案 3.1 遗传算法 3.2 构思 3.2.1 核心定义的类 3.2.2 常用类 ...
- 研发效能提升最佳实践的探索
GIAC(GLOBAL INTERNET ARCHITECTURE CONFERENCE)是长期关注互联网技术与架构的高可用架构技术社区和msup推出的,面向架构师.技术负责人及高端技术从业人员的年度 ...
- 本周五丨数据库智能管控最佳实践与探索
数据库管控能力的高低直接影响了企业数字化转型的进程,甚至于关乎成败.面对日趋丰富的业务场景和复杂的数据库环境,要做好数据库的管控工作,势必要引入云化.平台化.智能化的架构设计与技术. 那么本次云和恩墨 ...
- 软件架构中的架构模式和最佳实践:探索和实践
作者:禅与计算机程序设计艺术 "架构"这个词汇一直是软件工程师们谈论的热点话题之一,无论从代码设计.框架选型.需求分析.项目管理.测试策略还是后续的维护.运维等各个方面都离不开架构 ...
- 如何理性的调整「rwnd」和「cwnd」的大小
很多人常常对TCP优化有一种雾里看花的感觉,实际上只要理解了TCP的运行方式就能掀开它的神秘面纱.Ilya Grigorik 在「High Performance Browser Networking ...
- 99%的人都能看懂的分布式最佳「补偿」实践
来源:跨界架构师 「补偿」机制的意义 以电商的购物场景为例: 客户端 ---->购物车微服务 ---->订单微服务 ----> 支付微服务. 这种调用链非常普遍. 那么为什么需要考虑 ...
- 99% 的人都能看懂的「补偿」以及最佳实践
https://www.infoq.cn/article/0lMOVdP-kqWvbAa5QiEo 也许你对降级已经有了一些认识,这次,我们来聊一聊在保证对外高可用的同时,憋出的"内伤&qu ...
- 分布式系统关注点(8)——99%的人都能看懂的「熔断」以及最佳实践
如果这是第二次看到我的文章,欢迎右侧扫码订阅我哟~ > 本文长度为3319字,建议阅读9分钟. 阅读目录 熔断是什么 熔断怎么做 做熔断的最佳实践 总结 当我们工作所在的系统处于分布式系统初期 ...
- 从云原生到智能化,深度解读行业首个「视频直播技术最佳实践图谱」
在2022阿里云直播峰会上,多位直播产业领域技术专家与行业先行者,共同探讨超视频化时代视频直播技术的演进趋势与未来发展.会上,阿里云重磅发布了行业首个「视频直播技术最佳实践图谱」,将直播技术归纳总结为 ...
最新文章
- Linux最常用命令:简单易学,但能解决95%以上的问题
- 汇编原理实验--输出ASCII码10H到100H
- rac 火星舱如何备份oracle_Oracle数据库(RAC)巡检报告
- Android ListView避免多线程加载一个同一资源
- 混凝土静力受压弹性模量试验计算公式_【小马建考干货】天天送检,你知道混凝土试块检测哪些性能标指吗?...
- 计算机组成原理 北理,北京理工大学计算机组成原理期末复习.pdf
- linux用户组和权限分配
- Ubuntu系统安装VMware Tools的简单方法
- liunx中查看安装软件和卸载软件和启动程序
- android 菜鸟面单打印_关于菜鸟的圆通电子面单打印
- 分享两个线+标注的SLD样式
- 瀛洲大学计算机专业毕业 卖身,目前计算机芯片 ( 集成电路 ) 制造的主要原料 } 是 () ,它是一种可以在沙子中提炼出的物质。_学小易找答案...
- react结合rust编写wasm图像处理
- 悟空CRM在保险行业的应用
- 金字塔打印(C语言)
- 项目经理多为技术出身之怪相
- scp命令密码写命令里_使用命令查看wifi密码
- Java基础算法题(07):输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
- NBU备份rac恢复到single
- python 冷门知识点_Python中的10条冷门知识