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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

JavaScript凌厉开发

JavaScript凌厉开发

张鑫 黄灯桥、杨彦强 / 清华大学出版社 / 2010 年4月 / 49.00元

本书详细介绍Ext JS框架体系结构,以及利用HTML/CSS/JavaScript进行前端设计的方法和技巧。作者为Ext中文站站长领衔的三个国内Ext JS先锋,在开发思维和开发经验上有着无可争议的功力。 本书包含的内容有Ext.Element.*、事件Observable、Ext组件+MVC原理、Grid/Form/Tree/ComboBox、Ajax缓存Store等,并照顾JavaSc......一起来看看 《JavaScript凌厉开发》 这本书的介绍吧!

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

RGB HEX 互转工具

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

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具