React Hooks — The Ins and Outs

栏目: IT技术 · 发布时间: 4年前

内容简介:E.g.There are a few drawbacks with HOC.

React Hooks — The Ins and Outs

Hooks are functions that let you “hook into” React state and lifecycle features from function components.

React Hooks — The Ins and Outs

Why hooks

How did we reuse stateful logic — HOC

E.g.

import { withRouter } from "react-router-dom";
import { Form } from 'antd';function A(props) {
  const {
    match: { params },
    history,
    form
  } = props;  return <div> test </div>;
}export default withRouter(Form.create()(A))

There are a few drawbacks with HOC.

  • wrapper hell of components. HOC actually returns a new component that wraps the original component.
  • unclear dependencies: from the view of Component A , we have no way to clearly know this.props.form is from Form.create HOC, and this.props.history is from withRouter HOC
  • naming conflicts: imagine that Form.create and withRouter both inject a prop with the same name, which can easily happen as they are two separate HOCs that are properly maintained by two teams

How can we improve with Hooks

import { useHistory } from "react-router-dom";
import { Form } from 'antd';export default function A(props) {
  const [form] = Form.useForm();
  const history = useHistory();  return <div> test </div>;
}
  • no wrapper any more as they are all at the same level
  • clear dependencies as they are from separate hooks call: form from useForm and history from useHistory
  • no naming conflicts as they are from separate hooks and you can rename hooks return values

Hooks in practice

To implement a controlled Input element with reset functionality, we can do it this way :

import React, { useState } from "react";
import { Input, Button } from 'antd';export default function App() {
  const initialValue = 'please enter something';
  const [inputValue, setInputValue] = useState(initialValue);  return (
    <div className="App">
        // note the value is from e.target
      <Input value={inputValue} onChange={e => setInputValue(e.target.value)}/>
      <Button onClick={() => setInputValue(initialValue)}> Reset </Button>
    </div>
  );
}

There are a couple of stateful logic that we can abstract and resue.

  • value fetch — e.target.value
  • reset logic — reset to initial value

custom hook — useEventTarget

import { useState, useCallback } from "react";export default function useEventTarget(initialValue = "") {
  const [value, setValue] = useState(initialValue);
  const onChange = useCallback(e => setValue(e.target.value), []); // reusable value fetch logic
  const reset = useCallback(() => setValue(initialValue), [initialValue]); // resuable reset logic  return {
    value,
    onChange,
    reset
  };
}

The above example can then be refactored with custom useEventTarget hook:

import React from "react";
import { Input, Button } from "antd";
import useEventTarget from "./useEventTarget";export default function App() {
  const { value, onChange, reset } = useEventTarget("please enter something");  return (
    <div className="App">
      <Input value={value} onChange={onChange} />
      <Button onClick={reset}> Reset </Button>
    </div>
  );
}

Mental overhead

Hooks is NOT a substitute for class lifecycles though useEffect can simulate what lifecycles do. Hooks facilitates reusing stateful logic but it comes with costs.

Assume that I need a page that display count which is from zero and increment by one per second.

import React, { useState, useEffect } from 'react';export default function SetInterval() {
  const [ count, setCount ] = useState(0);  useEffect(() => {
    const interval = setInterval(() => {
      console.log("interval count", count); // count is always 0
      setCount(count + 1);
    }, 1000);
    return () => {
      clearInterval(interval)
    }
  }, []);  return <div> normal count is { count } </div>;
}

With the code above , the count on the page will stay on 1. This is due to the fact that useEffect call only runs on mount (as useEffect dependency is set to [] on line 14) and the count value at that point is 0 (i.e the initial value we set with useState call on line 4). Each time the interval function is called, the count value will always be 0 as it’s a closure variable. Therefore, setCount(count + 1) will be setCount(1).

Solution 1 — useEffect dependencies

Specify the dependencies if your useEffect depends on outer variables

import React, { useState, useEffect } from "react";export default function SetInterval() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    const interval = setInterval(() => {
      console.log('interval count', count); // increment by one per run
      setCount(count + 1);
    }, 1000);    return () => {
      // each time count value changes (i.e per second, clear the interval and init one with new count value
      console.log('interval clear', count); 
      clearInterval(interval);
    }
  }, [count]);  return <div> dep count is {count} </div>;
}

Solution 2 — use state callback

import React, { useState, useEffect } from "react";export default function SetInterval() {
  const [count, setCount] = useState(0);  useEffect(() => {
    const interval = setInterval(() => {
      // it doesnt matter what count was, it tells React to increment by one with previous value
      setCount(a => a + 1);
    }, 1000);    return () => {
      clearInterval(interval);
    };
  }, []);  return <div> prev normal count is {count} </div>;
}

Solution 3 — useRef

import React, { useRef, useState, useEffect } from "react";export default function SetInterval() {
  const [count, setCount] = useState(0);
  const ref = useRef();
  ref.current = count;  useEffect(() => {
    const interval = setInterval(() => {
      console.log("interval count", ref.current);
      setCount(ref.current + 1);
    }, 1000);    return () => {
      clearInterval(interval);
    };
  }, []);  return <div> ref count is {count} </div>;
}

Notice

  • If you want to follow the latest news/articles for the series of my blogs, Please 「Watch」 to Subscribe.

以上所述就是小编给大家介绍的《React Hooks — The Ins and Outs》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

数字化生存

数字化生存

(美)Nicholas Negroponte(尼古拉·尼葛洛庞帝) / 胡泳、范海燕 / 电子工业出版社 / 2017-1-1 / 68.00

《数字化生存》描绘了数字科技为我们的生活、工作、教育和娱乐带来的各种冲击和其中值得深思的问题,是跨入数字化新世界的*指南。英文版曾高居《纽约时报》畅销书排行榜。 “信息的DNA”正在迅速取代原子而成为人类生活中的基本交换物。尼葛洛庞帝向我们展示出这一变化的巨大影响。电视机与计算机屏幕的差别变得只是大小不同而已。从前所说的“大众”传媒正演变成个人化的双向交流。信息不再被“推给”消费者,相反,人们或他......一起来看看 《数字化生存》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

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

在线图片转Base64编码工具

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

RGB CMYK 互转工具