在 React Native 中使用 Hooks
React官方在 2018 ReactConf 大会上宣布 React v16.7.0-alpha(内测) 将引入 Hooks。什么是Hooks,我们来了解一下。
什么是Hooks?
在平时开发过程中,我们一般都会遇到如下问题:
1. 难以重用和共享组件中的与状态相关的逻辑2. 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面。3. 由于业务变动,函数组件不得不改为类组件等等。复制代码
上面说起来比较抽象,接下来我们以 键盘Api Keyboard 为例说明问题。
export default class App extends Component {constructor(props) {super(props);this.state = {isShowKeyboard: false}}static getDerivedStateFromProps() {this.keyboardDidShowListener = Keyboard.addListener("keyboardDidShow",this.keyboardDidShowHandler);}keyboardDidShowHandler () {this.setState({isShowKeyboard: true});}componentWillUnmount() {this.keyboardDidShowListener.remove();}render() {return (<View style={styles.container}><Text>当前键盘状态: {this.state.isShowKeyboard}</Text></View>);}
}复制代码
上面的代码用例比较简单,使用 Keyboard 注册监听键盘的显示、隐藏状态。可以看到键盘事件的注册,注销,状态的render都放在了Component中,如果当前Component中涉及很多这样的逻辑,会造成当前Component职责非常重,并且状态数据不能共享,当在另一个Component中需要监听键盘事件时,需要重新编写或Copy重复代码,冗余非常严重,对于功能维护和扩展都不是一件好事。 Hooks的出现解决了上面的问题,它允许开发者定义函数组件,也可以使用类组件(class components)的 state 和 组件生命周期,而不需要在 mixin、 函数组件、HOC组件和 render props 之间来回切换。方便我们在业务中实现业务逻辑代码的分离和组件的复用。与使用 setState 相比,组件是没有状态的。来看看使用Hooks的方式:
import { useState, useEffect } from 'react';
import {Keyboard
} from 'react-native';export default function keyboard() {const [keyboardStatus, setKeyboardStatus] = useState(false);Keyboard.addListener("keyboardDidShow",this.keyboardDidShowHandler);useEffect(()=> {return ()=> Keyboard.removeListener("keyboardDidShow",()=> setKeyboardStatus(true));}, [false]);return (<Text>当前键盘状态:{keyboardStatus}</Text>)
}复制代码
上述代码中将关于键盘的业务逻辑剥离到了函数中,称之为 函数组件。当我们在其他Component中使用时,只需要导入进来即可。在函数组件中,我们使用到了 useState、useEffect,它们作为Hooks中提供的Api,起到了什么作用呢?
Hooks Api
官方提供了 hooks 的三个关键的Api,分别是 State Hooks 、 Effect Hooks 、Context Hooks、 Custom Hooks(自定义hooks)。
useState
useState 这个方法可以为函数组件带来 local state,它接收一个用于初始 state 的值,返回一对变量
// 等价于const keyboardStatus= useState(0)[0];const setKeyboardStatus= useState(0)[1];复制代码
理解起来比较简单,其实就是定义 state 状态值,以及修改该 state 状态值的行为函数。
useEffect
useEffect 可以简单的理解为替代如下生命周期:
componentDidMount、componentDidUpdate、componentWillUnmount
useEffect 的代码既会在第一次初始化时(componentDidMount)执行,也会在后续每次触发 render 渲染时(componentDidUpdate)执行,返回值在组件注销时(componentWillUnmount)执行。结合上面的例子:
useEffect(()=> {// return 将会在组件注销时调用return ()=> Keyboard.removeListener("keyboardDidShow",()=> setKeyboardStatus(true));
}, [false]);复制代码
useEffect 的第二个参数,作为性能优化的设置,决定是否执行里面的操作来避免一些不必要的性能损失。只要第二个参数数组中的成员的值没有改变,就会跳过此次执行。如果传入一个空数组 [ ],那么只会在组件 mount 和 unmount 时期执行。
Context Hooks
React 16.3 版本中发布了全新的Context API。目的为了解决子组件嵌套层级过深,父组件的属性难以传达的问题。使用方式不算复杂,首先要利用 Context API创建一个数据提供者(Provider)和数据消费者(Consumer)。(说到这里有点像Java多线程并发的例子)在提供者所在的地方存入数据,在消费者所在的地方取出数据。简单看下 Context 使用方式: (1)创建上下文环境
// 创建 Contextimport React from 'react';const DataContext = React.createContext({ name: '', age: 23});
export default DataContext;
复制代码
(2)定义数据提供者 Provider
export default class App extends Component {render() {return (<DataContext.Provider value={{ name: 'Songlcy', age: 27 }}><CustomComponent /></DataContext.Provider>);}
}复制代码
(3)定义数据消费者 Consumer
export default class CustomComponent extends Component {render() {return (<DataContext.Consumer>{context => (<Text>我的名字:{context.name}, 我的年龄:{context.age}</Text>)}</DataContext.Consumer>)}
}复制代码
当组件嵌套层次很深的情况下,Context 的优势就会更为明显。 “诶,醒醒!”..... 说了这么多,继续回到Hooks。上面代码中,从 Context — Provider — Consumer 获取到数据,整个取值过程还是比较繁琐的。当我们要从多个 Consumer 中取值的时候,还要进行函数嵌套,更加麻烦。 useContext 是对 Context API 的简化。来看看简化后的样子:
const { name, age } = useContext(DataContext);复制代码
“我靠!这就完了?” 是的,取值过程就是这么简单,就是这么任性。再来10个 Consumer 又如何!
Custom Hooks
Custom Hooks 即自定义Hooks行为方式,本身并不是Api。核心概念就是将逻辑提取出来封装到函数中,具体实现就是通过一个函数封装跟状态数据(State)有关的逻辑,将这些逻辑从组件中抽取出来。在这个函数中我们可以使用其他的 Hooks,也可以单独进行测试。修改上面的例子:
export default function useKeyboardStatus() {const [keyboardStatus, setKeyboardStatus] = useState(false);Keyboard.addListener("keyboardDidShow",this.keyboardDidShowHandler);useEffect(()=> {return ()=> Keyboard.removeListener("keyboardDidShow",()=> setKeyboardStatus(true));},[]);return keyboardStatus;
}复制代码
代码几乎相同,唯一区别是函数名称用了 use* 前缀,这里需要遵循一个约定,命名要用 use* 。
Hooks 工作原理
“神马?Hooks 其实就是一个数组!”
回忆下最初我们使用 useState 时的方式:
const [keyboardStatus, setKeyboardStatus] = useState(false);复制代码
其实从这句代码我们也能猜出大致的实现思想:
使用一个类似于 setter 的函数作为hook函数中的第二个数组项返回,而 setter 将控制由hook管理的状态(State),状态由第一个数组项返回。
我们可以理解成有两个数组,分别存放 state、setState对应的方法。 当useState()第一次运行时,将setter函数推送到setter数组,状态推送到state数组。每个setter都有一个对它的光标位置的引用,因此通过触发对任何setter的调用,它将改变状态数组中该位置的状态值。说白了就是有个索引,setter方法根据索引修改对应的状态数据值。来看看伪代码的实现方式:
let state = []; // 存放state状态数据
let setter = []; // 存放 setXXX方法
let initial = true; // 是否是第一次运行
let index = 0;useState(initVal) {if (initial) {state.push(initVal);setter.push(createSetter(index));initial = false;}const setter = setter[index];const value = state[index];index++;return [value, setter];
}createSetter(index) {return function setterWithIndex(newVal) {state[index] = newVal;};
}复制代码
具体的源码实现,感兴趣的大家可以去看看。不过不建议每步都弄懂,了解了实现思想就可以了。
总结
状态和相关的处理逻辑可以按照功能进行划分,不必散落在各个生命周期中,大大降低了开发和维护的难度。除了这几个hooks还有其他额外的hooks:Hooks API Reference
最后推荐两个个很牛逼的库:
react-use: 封装了各种 Hooks。
eslint-plugin-react-hooks: Hooks ESLint 插件。
一个老外写的很不错的 React Native Hooks 文章:React Hooks Basics— Building a React Native App with React Hooks
转载于:https://juejin.im/post/5ce749b8e51d454f73356cb6
在 React Native 中使用 Hooks相关推荐
- 如何在React Native中使用react-navigation 5处理导航
React-navigation is the navigation library that comes to my mind when we talk about navigation in Re ...
- 理解 React Native 中的 AJAX 请求
曾经,大多数 Web 应用程序通过用户操作刷新整个网页以与 Web 服务器通信. 后来,AJAX(异步 JavaScript 和 XML)概念通过提供一种在后台与 Web 服务器通信的方式使 Web ...
- 我在React Native中构建时获得的经验教训
by Amanda Bullington 通过阿曼达·布林顿(Amanda Bullington) 我在React Native中构建时获得的经验教训 (Lessons I learned while ...
- 如何在React Native中写一个自定义模块
前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...
- 如何在React Native中记录日志?
本文翻译自:How to do logging in React Native? 如何为Web开发时在React Native中记录变量,例如使用console.log ? #1楼 参考:https: ...
- react native中一次错误排查 Error:Error: Duplicate resources
最近一直在使用react native中,遇到了很多的坑,同时也学习到了一些移动端的开发经验. 今天在做一个打包的测试时,遇到了一个问题,打包过程中报错"Error:Error: Dupli ...
- Android之React Native 中组件的生命周期
React Native 中组件的生命周期 概述 就像 Android 开发中的 View 一样,React Native(RN) 中的组件也有生命周期(Lifecycle).所谓生命周期,就是一个对 ...
- 如何在 React Native 中写一个自定义模块
前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...
- 了解React Native中的不同JavaScript环境
by Khoa Pham 通过Khoa Pham 了解React Native中的不同JavaScript环境 (Get to know different JavaScript environmen ...
- 如何在React Native中使用Redux Saga监视网络更改
by Pritish Vaidya 通过Pritish Vaidya 如何在React Native中使用Redux Saga监视网络更改 (How to monitor network change ...
最新文章
- 路由器snmp配置_基于keepalived配置数据库主从实现高可用
- golang怎么给空结构体赋值
- Rabbit的Windows安装
- Linux中的history命令
- PHP生成Mysql数据字典
- 高露洁、悦诗风吟、Benefit,618大促的数字化难题都是如何解决的?
- Linux使用LVM逻辑卷 给分区扩容 不重启 热扩容
- linux-LINUX试题
- “电”亮数字生活,阿里云助力南方电网智能调度
- cad快速选择命令快捷键_CAD快捷键命令大全
- Java基础Day05
- 永中java的窗口_永中國際 Office
- qt编写的mask遮罩的半透明涂抹功能
- 中古消费热潮下,爆爆奢漫步二奢直播新时代
- Compensating-Transaction模式
- 浅析STM32H7 FDCAN(一)
- Velodyne 32E pcap包GPS时间戳解析
- 制作一个带rEFInd引导菜单的WinPE启动光盘
- 面经02-深信服面试
- 一个能测试怀孕的软件,四个方法测怀孕 准爆了
热门文章
- android wifi操作,热点创建
- 小游戏策划案例精选_小游戏策划方案
- python---用python实现选择排序
- chown: `mysql#039;: invalid user_centos无法正常启动,报chown: invalid user:'root:root'
- java空指针找不到,跪空指针异常,所有的传入参数都判断了非空,实在找不到哪里没有赋值了...
- android改变textview文字,如何在Android TextView中更改文本
- 性能可靠服务器虚拟化,服务器虚拟化分析
- python warning_warning最新:Python 忽略warning的输出方法_爱安网 LoveAn.com
- mysql on 子句_ON子句中的MySQL未知列
- Python 爬虫经常需要睡眠防止被封IP time sleep