在 React Native 中使用 Hooks

栏目: 服务器 · 发布时间: 4年前

内容简介:React官方在 2018 ReactConf 大会上宣布 React v16.7.0-alpha(内测) 将引入 Hooks。什么是Hooks,我们来了解一下。在平时开发过程中,我们一般都会遇到如下问题:上面说起来比较抽象,接下来我们以 键盘Api

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机动画的算法基础

计算机动画的算法基础

鲍虎军 金小刚 彭群生 / 浙江大学出版社 / 2000-12 / 60.00元

《计算机应用技术前沿丛书:计算机动画的算法基础》主要内容简介:20世纪是一个科技、经济空前发展的时代,从世纪初相对论、量子理论的创立到今天以信息产业为龙头的高科技产业成为经济发展的第一支柱,人类社会发生了根本性的变革。而在这场以科学技术为社会发展直接动因的变革中,意义最深远、影响最广泛的就是计算机及其相关技术的发展和应用。在过去的50年里,计算机已从最初的协助人类进行精密和复杂运算的单一功能的运算......一起来看看 《计算机动画的算法基础》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具