初识react新功能Hooks

概述
hooks 是一个让你在不使用类的情况下还能使用state和别的一些react功能的新功能(React v16.7.0-alpha版本)

hooks是向后兼容的,这篇文章给有React使用经验的小伙伴提供了一个概述。

下面这个例子定义了一个计数器,当点击按钮的时候。计数器就会加1

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

这上面的例子中useState 就是一个hook,我们在函数里面调用它来添加一些局部的状态。react在重新渲染的时候保存这个状态值,
useState 返回了一个状态值(count)和一个能改变状态值的函数(setCount),你可一再事件或者别的地方来调用这个函数。它除了没有把新的状态值和旧的状态值合并以外别的和class里面的this.setState()都很相似(这里有个例子比较useState和this.state()
useState 唯一的参数是初始化的值。就像上面的例子中,初始化的值是0。
注意:和this.state不一样、这里的state你不必非得定义成一个对象。当然你也可以把它定义成一个对象,初始值只会在第一次被渲染的时候用到

定义多个状态变量

你可以在单个组件里多次使用State hook

function ExampleWithManyStates() {
  // 定义多个state变量
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

数组的解构语法可以让你在调用useState的时候给satate变量定义不同的名字,这些名字不是useState API的一部分。相反的,React假设你每一次渲染的时候多次调用了useState,而每次渲染都是相同的顺序执行.我们会回想一下为什么这样做,当这对以后有用

什么是Hook
钩子是允许从功能组件(function component)“挂钩”React状态和生命周期功能的功能。钩子在类内部不起作用 – 它让你在不依赖类的去情况下使用React(我们不推荐你马上重写已经存在的组件,但是你可以尝试在新的组件里使用Hook)
React 提供了一些内置的Hooks,比如useState。你也可以创建自己的Hooks以在不同组件中重用

Effect Hook
你之前可能是从React组件里执行数据提取,订阅或手动更改DOM。我们将这些操作称为“函数副作用”(或简称为“效果”),因为它们会影响其他组件,并且无法在渲染过程中完成。
Effect Hook中的useEffect增加了在功能组件函数副作用的功能。它与React类中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的目的,但是将这些钩子统一为单个API。(useEffect与Class钩子函数比较。

例如,组件在React更新了Dom后设置了文档标题

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // 和componentDidMount ,componentDidUpdate很相似
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

当你调用useEffect,就是在告诉React在刷新DOM后调用你的’effect’函数,Effects 被定义在组建内容, 这样就可以访问到组件的props和state,默认情况下,React每一次执行render后(包括第一次render)都会执行effects(进一步讨论useEffect和Class生命周期的比较
Effects也可以指定返回函数来清理状态,下面这个例子,组件使用effect 订阅了好友的在线状态,又通过unsubscribing 来清理状态。(Effects的返回函数相当于componentwillmount)

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

在这个例子里面,当组件将被卸载以及重新运行effect导致的渲染之前,React会取消对ChatApi的订阅(如果有需要,在props.friend.id的值没有改变的情况下, 我们可以告诉React跳过重新订阅

就像useState一样, 你可以在组建中多次使用effect

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

Hooks允许你通过哪些部分相关(例如添加和删除订阅)来组织组件中的函数副作用,而不是基于生命周期方法强制拆分

Hooks的拆分
钩子是js函数,但它们加入了两个额外的规则:

  • 只能在顶层调用Hooks。不要在循环语句,条件语句或嵌套函数里调用Hook
  • 只能React功能组件调用Hooks。 不能从普通JavaScript函数中调用Hook。 (还有一个地方能合法的使用Hooks – 你自己的定制Hooks。)

构建你自己的Hooks
有的时候,我们希望在组件之间重用一些有状态逻辑。一般来说,这个问题有两种流行的解决办法:高阶组件render props。Custom Hooks允许你执行这样的操作,并且不需要在代码树中添加更多组件。
在文章的早些部分,我们介绍了一个FriendStatus 组件调用useState和useEffect Hooks来订阅朋友的在线状态。如果我们还想要在另一个组件中重用此订阅逻辑。
首先,我们将这个逻辑提取到一个名为useFriendStatus的自定义Hook中:

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

这个组件接受一个friendID 作为参数,然后返回我们的朋友是否在线。
现在我们就可以在下面的两个组件中使用它

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

这些组件的状态是完全独立的,Hooks是重用状态逻辑的一种方式,而不是状态本身。事实上,每一次Hook调用都是一个完全单独的状态 – 所以你甚至可以在一个组件中多次定义一个相同的Hook。
custom hook更像是一种惯例而非功能。如果函数的名字以use开头并且它调用其他Hook,我们就称它为一个Custom Hook。useSomething命管理是linter插件如何使用Hooks在代码中查找错误。

Other Hooks
你可能会发现一些很少用的内置Hook很有用。例如,useContext允许订阅React上下文而不引入嵌套:

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

useReducer允许使用reducer管理复杂组件的本地状态:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

下一步
State Hook 文开始吧

    原文作者:菠菜
    原文地址: https://segmentfault.com/a/1190000017088114
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞