React-Hooks-入门

76次阅读

共计 2388 个字符,预计需要花费 6 分钟才能阅读完成。

React Hook 是 React16.8 提出来的一个新特性,其意义就在于我们可以让函数组件变得跟类组件一样有能力管理自己的状态,这意味着我们以后写的所有组件都可以是 Function,对于初学者来说降低了学习成本(压根不用管 this 是个啥),而且我们可以自定义 hook,能够提高状态逻辑的复用,从而也便于维护。

State Hooks

useState

  • react 为我们提供了 useState 这个函数,使用此函数就可以取代我们之前的每个组件的状态管理了;
import {useState} from 'react'
function count() {
    // useState 函数为我们解构了一个变量 num 和一个 setNum 函数,并且将变量初始值赋值为“0”const [num, setNum] = useState("0");
    // 我们在这里读取 num 的值,并且每点击一次按钮都会使 num+1
    return <button onClick={() => {setNum(num + 1)}}>{num}</button>
}
  • 当我们每次改变 num 的值时,就会重新执行 count 函数,不过不用担心,num 的初始化只会执行一次;

useReducer

  • 其实 useState 也是基于 useReducer 的,用过 redux 的人对 reducer 不陌生,reducer 是一个纯函数,会根据 action 中 type 的不同返回改变后新的状态;
import {useReducer} from 'react'
// 创建一个 reducer
function myReducer(state, action){switch(action.type) {
        case "add": return state + 1
        case "minus": return state -1
        default:
         return state
    }
}
// 函数组件 
function count() {
    // 传入 reducer 和初始值
    const [num, dispatchNum] = useReducer(myReducer, "0");
    return <button onClick={() => {dispatchNum({type: "add"})}}>{num}</button>
}

Effect Hook

  • Effect Hook 可以看作是代替了一些生命周期函数
import {useState, useEffect} from 'react'

function count() {const [num, setNum] = useState("0");
    useEffect(() => {const interval = setInterval(() => {setNum(num + 1)
        }, 1000)
        // 最后要 return 一下,记得清除定时器
        return () => clearInterval(interval)
    }, [num])
    return <button onClick={() => {setNum(num + 1)}}>{num}</button>
}
  • useEffect 函数中第一个参数为组件第一次渲染时执行的函数(最后 return 的是定时器卸载的函数,可以看作是 componentWillUnMount 生命周期内做的事),第二参数表示依赖的值,只有依赖的值变化时,useEffect 才会重新执行;

Context Hook

  • 顾名思义这是一个上下文 hook
// 新建一个 context 文件 myContext.js
import React from 'react'
export default React.createContext("")
// 在另一个文件中引入
import MyContext from './myContext'
// 通过 MyContext.Provider 传值
<MyContext.Provider value="test">
    <Component/>
</MyContext.Provider>
// 在组件中使用
import {useContext} from 'react'
import MyContext from './myContext'
function test() {const contextValue = useContext(MyContext)
    return <div>{contextValue}</div>
}

Ref Hook

import {useRef} from 'react'
function testRef() {const inputRef = useRef()
    useEffect(() => {console.log(inputRef)
    })
    return <input ref={inputRef}> 测试 ref</input>
}

自定义 Hook

  • hook 其实就是一个函数,在这个函数里我们也可以使用其它 hook, 自定义的 hook 要以 use 开头, 下面是官网上的例子,已经很好了;
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';
}

文章已同步到 陈晓拉尼 个人博客

正文完
 0

React-Hooks入门

76次阅读

共计 5471 个字符,预计需要花费 14 分钟才能阅读完成。

学习目标

在本文结束时,您将能够回答以下问题:

  • 什么是 hooks?
  • 如何使用 hooks?
  • 使用 hooks 的一些规则?
  • 什么是 custom hook(自定义钩子)?
  • 什么时候应该使用 custom hooks?
  • 使用 custom hooks 有什么好处?

什么是 hooks?

Hooks 可以做到以下事情:

  • 在功能组件中使用 state 和“hook into”的生命周期方法。
  • 在组件之间重用有状态逻辑,这简化了组件逻辑,最重要的是,让你跳过编写 classes。

如果你已经使用过 React,你就会知道复杂多变,有状态的逻辑是如何得到的,当应用程序为功能添加了几个新功能时,就会发生组件代码变得复杂而难以维护这种情况。为了尝试简化这个问题,React 背后的大脑试图找到解决这个问题的方法。

(1)在组件之间重用有状态逻辑

hooks 允许开发人员编写简单,有状态的功能组件,并在开发时花费更少的时间来设计和重构组件层次结构。怎么样?使用钩子,您可以在组件之间_获取_和_分享_有状态逻辑。

(2)简化组件逻辑

当您的应用程序中出现不可避免的指数级逻辑增长时,简单的组件就回因为各种状态逻辑和生命周期等等因素,而变得繁琐和复杂。组件的职责增长并变得不可分割。反过来,这使编码变得麻烦并且测试困难。

class 是 React 架构的重要组成部分。class 有许多好处,但它们为初学者创造了入门的障碍。对于 class,您还必须记住将 this 绑定到事件处理程序,因此代码可能变得冗长且有点多余。

如何使用 hooks?

React 版本 16.8.

import {useState, useEffect} from 'react';

很简单,但你如何实际使用这些新方法?以下示例非常简单,但这些方法的功能非常强大。

useState hook 方法

使用状态钩子(state hook)的最好方法是对其进行解构并设置原始值。第一个参数将用于存储状态,第二个参数用于更新状态。

例如:

const [weight, setWeight] = useState(150);
onClick={() => setWeight(weight + 15)}

weight 是状态

setWeight 是一种用于更新状态的方法

useState(150)是用于设置初始值(任何基本类型)的方法

值得注意的是,您可以在单个组件中多次构造状态 hook:

const [age, setAge] = useState(42);
const [month, setMonth] = useState('February');
const [todos, setTodos] = useState([{text: 'Eat pie'}]);

因此,该组件可能看起来像:

import React, {useState} from 'react';
export default function App() {const [weight, setWeight] = useState(150);
const [age] = useState(42);
const [month] = useState('February');
const [todos] = useState([{text: 'Eat pie'}]);
return (Current Weight: {weight}
      Age: {age}
      Month: {month}
       setWeight(weight + 15)}>
        {todos[0].text}


  );
}

useEffect 钩子方法

使用 effect hook 就好像使用 componentDidMount, componentDidUpdate, 和 componentWillUnmount 这类的生命周期的方法。

例如:

// similar to the componentDidMount and componentDidUpdate methods
useEffect(() => {document.title = You clicked ${count} times;
});

组件更新的任何时候,渲染后都会调用 useEffect。现在,如果你只想在变量 count 改变时更新 useEffect,你只需将该事实添加到数组中方法的末尾,类似于高阶 reduce 方法末尾的累加器。

// check out the variable count in the array at the end...
useEffect(() => {document.title = You clicked ${count} times;
}, [count]);

让我们结合两个例子:

const [weight, setWeight] = useState(150);
useEffect(() => {document.title = You weigh ${weight}, you ok with that?;
}, [weight]);
onClick={() => setWeight(weight + 15)}

因此,当触发 onClick 时,也会调用 useEffect 方法,并在 DOM 更新后在文档标题中呈现新的数据。

例:

import React, {useState, useEffect} from 'react';
export default function App() {const [weight, setWeight] = useState(150);
const [age] = useState(42);
const [month] = useState('February');
const [todos] = useState([{text: 'Eat pie'}]);
useEffect(() => {document.title = You weigh ${weight}, you ok with that?;
});
return (Current Weight: {weight}
      Age: {age}
      Month: {month}
       setWeight(weight + 15)}>
        {todos[0].text}


  );
}

useEffect 非常适合进行 API 调用:

useEffect(() => {fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then(results => results.json())
    .then((data) => {setTodos([{ text: data.title}]);
});
}, []);

React 钩子看起来很棒,但是如果你花一点时间,你可能会意识到在多个组件中重新初始化多个钩子方法,比如 useState 和 useEffect,可能会违背 DRY(Don’t repeat yourself)原则。那么,让我们看看如何通过创建自定义钩子来重用这些新内置方法。

关于使用 hooks 的一些规则?

是的,React 钩子有规则。这些规则乍一看似乎是非常规的,但是一旦你理解了 React 钩子如何启动的基础知识,规则就很容易理解。

(1) 必须在顶层以相同的顺序调用挂钩。(依次调用)
Hooks 创建一个钩子调用数组来保持秩序。这个命令有助于 React 告诉区别,例如,在单个组件中或跨应用程序的多个 useState 和 useEffect 方法调用之间。

例如:

// This is good!
function ComponentWithHooks() {
  // top-level!
  const [age, setAge] = useState(42);
const [month, setMonth] = useState('February');
const [todos, setTodos] = useState([{text: 'Eat pie'}]);
return (//...)
}

在第一次渲染时,42,February,[{text:’Eat pie’}]都被推入状态数组。

当组件重新渲染时,忽略 useState 方法参数。

age,month 和 todos 的值是从组件的状态中检索的,这是前面提到的状态数组。

(2) 无法在 条件语句或循环中 调用挂钩。
由于启动 hooks 的方式,不允许使用 within 条件语句或循环。对于 hooks,如果在重新渲染期间初始化的顺序发生变化,则很可能您的应用程序无法正常运行。您仍然可以在组件中使用条件语句和循环,但不能在代码块内使用钩子。

例如:

// DON'T DO THIS!!
const [DNAMatch, setDNAMatch] = useState(false)

if (name) {setDNAMatch(true)
  const [name, setName] = useState(name)

  useEffect(function persistFamily() {localStorage.setItem('dad', name);
}, []);
}

// DO THIS!!
const [DNAMatch, setDNAMatch] = useState(false)
const [name, setName] = useState(null)

useEffect(() => {if (name) {setDNAMatch(true)
    setName(name)
    localStorage.setItem('dad', name);
}
}, []);

(3) 钩子不能用在 class 组件中。
钩子必须在功能组件或自定义钩子函数中初始化。自定义钩子函数只能在功能组件中调用,并且必须遵循与非自定义钩子相同的规则。

您仍然可以在同一个应用程序中使用类组件。您可以使用 hooks 作为类组件的子项呈现功能组件。

(4) 自定义钩子应该以 单词 use 开头并且是驼峰式 的。
这是一个强有力的建议而非规则,但它将有助于您的应用程序的一致性。你也会知道,当你看到一个以“use”为前缀的函数时,它可能是一个自定义钩子。

什么是自定义钩子?

自定义挂钩只是遵循与非自定义挂钩相同规则的函数。它们允许您整合逻辑,共享数据以及跨组件重用钩子。

什么时候应该使用自定义 hook?

当您需要在组件之间共享逻辑时,最好使用自定义挂钩。在 JavaScript 中,当您想要在两个单独的函数之间共享逻辑时,您可以创建另一个函数来支持它。好吧,就像组件一样,hooks 也是 function。您可以提取 hooks 逻辑,以便在应用程序的组件之间共享。在编写自定义 hooks 时,您可以命名它们(再次以“use”开头),设置参数,并告诉它们应该返回什么(如果有的话)。

例如:

import {useEffect, useState} from 'react';
const useFetch = ({url, defaultData = null}) => {const [data, setData] = useState(defaultData);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {fetch(url)
      .then(res => res.json())
      .then((res) => {setData(res);
setLoading(false);
})
      .catch((err) => {setError(err);
setLoading(false);
});
}, []);
const fetchResults = {
    data,
    loading,
    error,
  };
return fetchResults;
};
export default useFetch;

使用自定义 hook 有什么好处?

Hooks 允许您在应用程序增长时抑制复杂性,并编写更易于理解的代码。下面的代码是两个具有相同功能的组件的比较。在第一次比较之后,我们将在伴随容器的组件中使用自定义钩子展示更多好处。

以下类组件应该看起来:

import React from 'react';
class OneChanceButton extends React.Component {constructor(props) {super(props);
this.state = {clicked: false,};
this.handleClick = this.handleClick.bind(this);
}

  handleClick() {return this.setState({ clicked: true});
}

  render() {
    return (You Have One Chance to Click);
}
}

export default OneChanceButton;

如何使用钩子实现相同的功能来简化代码并提高可读性:

import React, {useState} from 'react';
function OneChanceButton(props) {const [clicked, setClicked] = useState(false);
function doClick() {return setClicked(true);
}

  return (You Have One Chance to Click);
}

export default OneChanceButton;

结论

React hooks 是一个惊人的新功能!实施的理由是合理的; 并且,再加上这一点,我相信这将极大地降低 React 编码的门槛,并使其保持在最喜欢的框架之上列表。看到这会如何改变第三方库的工作方式,尤其是状态管理工具和路由器,将会非常令人兴奋。

总之,React 钩子:

  • 无需使用类组件即可轻松与 React 的生命周期方法相关联
  • 通过增加可重用性和抽象复杂性来帮助减少代码量
  • 帮助简化组件之间共享数据的方式

推荐阅读:https://juejin.im/post/5be8d3…

正文完
 0