成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React Hook起飛指南

姘擱『 / 2368人閱讀

摘要:起飛指南作者元瀟方凳雅集出品目前放出來了個(gè)內(nèi)置,但僅僅基于以下兩個(gè),就能做很多事情。行代碼實(shí)現(xiàn)一個(gè)全局元瀟根組件掛上即可子組件調(diào)用隨時(shí)隨地實(shí)現(xiàn)一個(gè)局部元瀟的本質(zhì)是的一個(gè)語法糖,感興趣可以閱讀一下的類型定義和實(shí)現(xiàn)。

React Hook起飛指南

作者:元瀟 方凳雅集出品

16.8目前放出來了10個(gè)內(nèi)置hook,但僅僅基于以下兩個(gè)API,就能做很多事情。所以這篇文章不會講很多API,也不會講API的基本用法,只把這兩個(gè)能做的事情講清楚,閱讀全文大概5-10分鐘。

狀態(tài)管理:useState

副作用管理:useEffect

這兩個(gè)api就是hook世界里的鐮刀和錘子,看似簡單的兩個(gè)api實(shí)際上所代表的,是相比以前截然不同的一種新的編程模型。

前言:已經(jīng)有了class component,為什么又來了一個(gè)hook?

Dan在他的博客上提到:

我們知道組件和自上而下的數(shù)據(jù)流可以幫助我們將大型UI組織成小型,獨(dú)立,可重用的部分。 但是,我們經(jīng)常無法進(jìn)一步破壞復(fù)雜組件,因?yàn)檫壿嬍怯袪顟B(tài)的,無法提取到函數(shù)或其他組件中。而hook讓我們可以將組件內(nèi)部的邏輯組織成可重用的隔離單元。

所以,一句話總結(jié)hook帶來的變革就是:將可復(fù)用的最小單元從組件層面進(jìn)一步細(xì)化到邏輯層面。

基于這一點(diǎn)優(yōu)勢,在后面我們看可以看到,基于hook開發(fā)的應(yīng)用里的所有組件都不會隨業(yè)務(wù)增長而變得臃腫,因?yàn)樵趆ook的世界里,狀態(tài)邏輯和UI是解耦的。UI只需要消費(fèi)最終計(jì)算出來的狀態(tài)數(shù)據(jù),hook只關(guān)注狀態(tài)的計(jì)算和改變。

一、有狀態(tài)的函數(shù)

useState組件是有狀態(tài)的:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  render() {
    return (
      

You clicked {this.state.count} times

); } }

函數(shù)是無狀態(tài)的:

const Example = props => {
  const { count, onClick } = props;
  return (
    

You clicked {count} times

); }

hooks是有狀態(tài)的函數(shù):

import { useState } from "react";
const Example = () => {
    const [count, setCount] = useState(0);
    return (
      

You clicked {count} times

); }

Think: useState生產(chǎn)出來的setter在更新state的時(shí)候不會合并,這點(diǎn)不同于傳統(tǒng)class組件的setState方法,為什么這樣設(shè)計(jì)?

// Don"t do such like this ↓
const [data, setData] = useState({ count: 0, name: "zby" });
useEffect(() => {
  // data: { count: 0, name: "zby" } -> { count: 0 }
  setData({ count: 1 });
}, []);

我們的應(yīng)用都是從小到大發(fā)展起來的,初始充分的組件劃分和狀態(tài)設(shè)計(jì)是保證應(yīng)用后續(xù)可維護(hù)性的重要一環(huán),因?yàn)殡S著應(yīng)用的擴(kuò)增,組件難免變得臃腫。所以有時(shí)我們也從一開始就一步到位引入redux之類的狀態(tài)管理。

但現(xiàn)在,在我們的“純函數(shù)”組件里,每個(gè)useState都會生產(chǎn)出一對兒state和stateSetter,我們無需考慮更多的狀態(tài)樹的設(shè)計(jì)和組件的劃分設(shè)計(jì),邏輯代碼直接從根組件寫起,漸進(jìn)式開發(fā)變得可行。

所謂“漸進(jìn)式”開發(fā):概括應(yīng)用的發(fā)展路徑大致可以分為以下3個(gè)階段:

1. 前期farm:
只需要把相關(guān) state 組合到幾個(gè)獨(dú)立的 state 變量即可應(yīng)付絕大多數(shù)情況;

2.中期gank:當(dāng)組件的狀態(tài)逐漸變得多起來時(shí),我們可以很輕松地將狀態(tài)的更新交給reducer來管理(詳情在下文第二章展開);

3.大后期團(tuán)戰(zhàn):不光狀態(tài)多了,狀態(tài)的邏輯也越來越復(fù)雜的時(shí)候,我們可以幾乎0成本的將繁雜的狀態(tài)邏輯代碼抽離成自定義hook解決問題(詳情在下文第三章展開);

基于hook,我們的開發(fā)過程,變得比以往更有彈性。所以這樣的漸進(jìn)式的開發(fā)變得可行且高效。

二、 高度靈活的redux,純粹、無依賴

上文說道,當(dāng)組件的狀態(tài)逐漸變得多起來時(shí),我們可以很自然的將狀態(tài)的更新交給reducer來管理。

不同于真正的redux,在實(shí)際應(yīng)用中,hook帶來了一種更加靈活和純粹的模式?,F(xiàn)在我們可以用10行代碼實(shí)現(xiàn)一個(gè)全局的redux,也可以用2行代碼隨時(shí)隨地實(shí)現(xiàn)一個(gè)局部的redux。

A:10行代碼實(shí)現(xiàn)一個(gè)全局redux:

import React from "react";
const store = React.createContext(null);
export const initialState = { name: "元瀟" };
export function reducer(state, action) {
  switch (action.type) {
    case "changeName": return { ...state, name: action.payload };
    default: throw new Error("Unexpected action");
  }
}
export default store;

Provider根組件掛上即可

import React, { useReducer } from "react";
import store, { reducer, initialState } from "./store";
function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
     
      
) }

子組件調(diào)用

import React, { useContext } from "react";
import store from "./store";
function Child() {
  const { state, dispatch } = useContext(store);
  ...
}

B:隨時(shí)隨地實(shí)現(xiàn)一個(gè)局部redux

import React, { useReducer } from "react";
const initialState = { name: "元瀟" };
function reducer(state, action) {
  switch (action.type) {
    case "changeName": return { ...state, name: action.payload };
    default: throw new Error("Unexpected action");
  }
}
function Component() {
  const [state, dispatch] = useReducer(reducer, initialState);
  ...
}

useState的本質(zhì)是useReducer的一個(gè)語法糖,感興趣可以閱讀一下hooks的類型定義和實(shí)現(xiàn)。

三、自定義hook

上上文說道,當(dāng)組件發(fā)展到一定程度,不光是狀態(tài)多了,狀態(tài)的邏輯也越來越復(fù)雜的時(shí)候,我們可以幾乎0成本的將繁雜的狀態(tài)邏輯代碼抽離成自定義hook解決問題。

當(dāng)我們想在兩個(gè)函數(shù)之間共享邏輯時(shí),我們會把它提取到第三個(gè)函數(shù)中。而組件和 hook 都是函數(shù),所以也同樣適用這種方式。不同的是,hook 是有狀態(tài)的函數(shù),它能實(shí)現(xiàn)以往純函數(shù)所不能做到的更高級別的復(fù)用——狀態(tài)邏輯的復(fù)用。

且先看下面兩個(gè)demo示例

A:class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: undefined
    };
  }
  componentDidMount() {
    service.getInitialCount().then(data => {
      this.setState({ count: data });
    });
    service.getInitialName().then(data => {
      this.setState({ name: data });
    });
  }
  componentWillUnmount() {
    service.finishCounting().then(() => {
      alert("計(jì)數(shù)完成");
    });
  }
  addCount = () => {
    this.setState({ count: this.state.count + 1 });
  };
  handleNameChange = name => {
    this.setState({ name });
  };
  render() {
    const { count, name } = this.state;
    return (
      

You clicked {count} times

); } }
B:function useCount(initialValue) {
  const [count, setCount] = useState(initialValue);
  useEffect(() => {
    service.getInitialCount().then(data => {
      setCount(data);
    });
    return () => {
      service.finishCounting().then(() => {
        alert("計(jì)數(shù)完成");
      });
    };
  }, []);
  function addCount() {
    setCount(c => c + 1);
  }
  return { count, addCount };
}
function useName(initialValue) {
  const [name, setName] = useState(initialValue);
  useEffect(() => {
    service.getInitialName().then(data => {
      setName(data);
    });
  }, []);
  function handleNameChange(value) {
    setName(value);
  }
  return { name, handleNameChange };
}
const App = () => {
  const { count, addCount } = useCount(0);
  const { name, setName } = useName();
  return (
    

You clicked {count} times

); };

A有2個(gè)狀態(tài):count和name,還有與之相關(guān)的一票兒邏輯,散落在組件的生命周期和方法里。雖然我們可以將組件的state和變更action抽成公共的,但涉及到副作用的action,到最終還是繞不開組件的生命周期。但一個(gè)組件的生命周期只有一套,不可避免的會出現(xiàn)一些完全不相干的邏輯寫在一起。如此一來,便無法實(shí)現(xiàn)完全的狀態(tài)邏輯復(fù)用。

在B中,我們將count相關(guān)的邏輯和name相關(guān)的邏輯通過自定義hook,封裝在獨(dú)立且封閉的邏輯單元里。以往class組件的生命周期在這里不復(fù)存在。生命周期是和UI強(qiáng)耦合的一個(gè)概念,雖然易于理解,但它天然距離數(shù)據(jù)很遙遠(yuǎn)。而hook以一種類似rxjs模式的數(shù)據(jù)流訂閱實(shí)現(xiàn)了組件的副作用封裝,這樣的好處就是我們只需要關(guān)心數(shù)據(jù)。所以hook所帶來的,絕不僅僅只是簡化了state的定義與包裝。

這個(gè)動(dòng)畫,很好的展示了A->B前后相關(guān)聯(lián)的狀態(tài)邏輯的組織方式變化。

業(yè)務(wù)實(shí)戰(zhàn)記錄:

這是一個(gè)商品詳情頁用到的SKU選擇組件

我們使用hook將原有的class組件進(jìn)行重構(gòu),這個(gè)重構(gòu)的過程就是一個(gè)狀態(tài)邏輯的抽取過程。

我們將組件核心的2個(gè)狀態(tài)和相關(guān)的邏輯,抽到了2個(gè)獨(dú)立的自定義hook中(見下圖)。這樣做的好處很明顯,我們的組件只需要去消費(fèi)這兩個(gè)hook產(chǎn)出的value和function,狀態(tài)的維護(hù)和更新細(xì)節(jié),已經(jīng)被封裝在hook里。

const { specPath, handleSpecPathChange } = useSkuSpecPath({
    defaultSpecPath,
    dataSource
  });
const { skus, handleSkuAmountChange } = useSkuAmount({
  defaultSelectedSkus,
  dataSource
});

在這里提出一個(gè)自定義hook的設(shè)計(jì)范式:

const { state, handleChange, others } = useCustomHook(config, dependency?);

其中config聲明了hook所需要的數(shù)據(jù),可能是內(nèi)部useState的初始值,也可能是結(jié)構(gòu)化的數(shù)據(jù),總結(jié)起來就是這個(gè)hook的配置

dependency通常只有hook內(nèi)使用了useEffect、useCallback這類API,需要我們聲明依賴的時(shí)候需要傳入。

左邊是重構(gòu)后的代碼(脫敏代碼,領(lǐng)會精神就好),原先核心的通用邏輯被抽到useSkuSpecPath和useSkuAmount這兩個(gè)hook里后,這個(gè)組件變成了它們的調(diào)用方。后續(xù)不管UI組件如何變化和擴(kuò)展,只要符合它們的接口格式約定,就可以隨時(shí)隨地地復(fù)用這些邏輯,很快地實(shí)現(xiàn)一個(gè)新的sku選擇組件。

總結(jié):自定義hook實(shí)現(xiàn)了狀態(tài)邏輯與UI分離,通過合理抽象自定義hook,能夠?qū)崿F(xiàn)非常高級別的業(yè)務(wù)邏輯抽象復(fù)用。

推薦一個(gè)網(wǎng)站,里面收集了一些有意思的自定義hook

四、未來引用Dan的一句話:
hook可以涵蓋class組件的所有使用場景,同時(shí)在抽取、測試和重用代碼方面提供了更大的靈活性。這就是為什么Hooks代表了我們對React未來的愿景。

react16.8以上的應(yīng)用里,大家可以立馬用起來了。

彩蛋

hook原理: Not magic,just array

let hooks, i;
function useState() {
  i++;
  if (hooks[i]) {
    // 再次渲染時(shí)
    return hooks[i];
  }
  // 第一次渲染
  hooks.push(...);
}
// 準(zhǔn)備渲染
i = -1;
hooks = fiber.hooks || [];
// 調(diào)用組件
Component();
// 緩存 Hooks 的狀態(tài)
fiber.hooks = hooks;

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/106775.html

相關(guān)文章

  • React Hook 不完全指南

    摘要:使用完成副作用操作,賦值給的函數(shù)會在組件渲染到屏幕之后。如此很容易產(chǎn)生,并且導(dǎo)致邏輯不一致。同時(shí),這也是很多人將與狀態(tài)管理庫結(jié)合使用的原因之一。當(dāng)我們通過的第二個(gè)數(shù)組類型參數(shù),指明當(dāng)前的依賴,就能避免不相關(guān)的執(zhí)行開銷了。 前言 本文內(nèi)容大部分參考了 overreacted.io 博客一文,同時(shí)結(jié)合 React Hook 官方 文章,整理并歸納一些筆記和輸出個(gè)人的一些理解 什么是 Hoo...

    Lin_R 評論0 收藏0
  • 盤點(diǎn) 9 月份 yyds 的開源項(xiàng)目

    摘要:地址勵(lì)志計(jì)算機(jī)教程勵(lì)志要成為一名谷歌軟件工程師,但沒有專業(yè)背景的他,只能通過自己的努力來達(dá)成理想。最終,雖然沒有去谷歌,但他人到中年,還順利成為了一名亞馬遜的技術(shù)專家,年薪百萬。 本文盤點(diǎn) 8 月份 GitHub 上 Star 數(shù)攀升最快的開源項(xiàng)目,他們分別是: 1.?GitHub 排...

    Cheng_Gang 評論0 收藏0
  • React教程:組件,Hooks和性能

    摘要:顧名思義,受控組件的值由控制,能為與用戶交互的元素提供值,而不受控制的元素不獲取值屬性。另外我發(fā)現(xiàn)受控組件更容易理解和于使用。只是一種把組件作為參數(shù)的函數(shù),并且與沒有包裝器的組件相比,能夠返回具有擴(kuò)展功能的新組件。其中三個(gè)基本的是,和。 翻譯:瘋狂的技術(shù)宅原文:https://www.toptal.com/react/... 本文首發(fā)微信公眾號:jingchengyideng歡迎關(guān)...

    edagarli 評論0 收藏0
  • 理解 React Hooks 的 Capture Value 特性

    摘要:在讀了一些文章后,大致是找到自己總是掉坑的原因了沒理解中的特性。通過這個(gè)示例,相信會比較容易地理解特性,并如何使用來暫時(shí)繞過它。在知道并理解這個(gè)特性后,有助于進(jìn)一步熟悉了的運(yùn)行機(jī)制,減少掉坑的次數(shù)。 由于剛使用 React hooks 不久,對它的脾氣還拿捏不準(zhǔn),掉了很多次坑;這里的 坑 的意思并不是說 React hooks 的設(shè)計(jì)有問題,而是我在使用的時(shí)候,因?yàn)檫€沒有跟上它的理念導(dǎo)...

    curlyCheng 評論0 收藏0
  • 精益 React 學(xué)習(xí)指南 (Lean React)- 1.3 React 組件

    摘要:無狀態(tài)組件除了可以通過來創(chuàng)建組件以外,組件也可以通過一個(gè)普通的函數(shù)定義,函數(shù)的返回值為組件渲染的結(jié)果。這就是為什么要有屬性,屬性能夠幫助定位與數(shù)組元素的關(guān)系,在重渲染的時(shí)候能夠?qū)崿F(xiàn)渲染優(yōu)化。 書籍完整目錄 1.3 React 組件 showImg(https://segmentfault.com/img/bVvLOW); 1.3.1 React 組件介紹 在 React 中組件是第一元...

    cyrils 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<