最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React Hooks的学习

    正文概述 掘金(星空_)   2021-04-30   410

    1、为什么学习hooks,hooks是什么,hooks有什么作用?

    Hook 是React16.8的新增特性,它是一个特殊的函数,可以让你“钩入” React 的特性,可以在不用编写class组件的情况下使用state以及其他的React特性。为什么要学习hook呢?因为我们在开发的时候,往往会遇到一些问题,例如:在组件之间复用状态逻辑困难复杂组件变得难以理解难以理解的class等等。Hook 在无需修改组件结构的情况下复用状态逻辑。Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分。还可以使用 reducer 来管理组件的内部状态,使其更加可预测。Hook还可以在不使用class的情况下,使用更多的React特性。

    2、HOOKS概览

    1、 使用 useState

    import React, { useState } from 'react';
    
    function Example() {
      // 声明一个叫 “count” 的 state 变量。
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>You clicked {count} times</p> {/*使用State时*/}
          <button onClick={() => setCount(count + 1)}> {/*更新state*/}
            Click me
          </button>
        </div>
      );
    }
    

    useState 唯一的参数就是初始 state,在例子中就是useState(0),0就是初始state。useState 会返回一对值:当前状态(count)和一个更新它的函数(setCount)。可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。以下是等价的class hook实现的例子:

    class Example extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count: 0
        };
      }
    
      render() {
        return (
          <div>
            <p>You clicked {this.state.count} times</p> {/*使用State时*/}
            <button onClick={() => this.setState({ count: this.state.count + 1 })}> {/*更新state*/}
              Click me
            </button>
          </div>
        );
      }
    }
    

    通过以上比较发现:在 class 中,通过在构造函数中设置 this.state{ count: 0 } 来初始化 count state 为 0,显示当前state时,需读取this.state.count,在函数中可直接使用count。更改state时,在 class 中,需要this.setState()来更新 count 值。在函数中,已经有了setCountcount变量,不需要 this

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

    在函数组件中没有 this,所以不能分配或读取 this.state。可直接在组件中调用 useState Hook,useState Hook可以在一个组件中多次使用,可以同时创建多个变量,在调用useState 时可以给 state 变量取不同的名字:

    import React, { useState } from 'react';
    
    function Example() {
      // 声明一个叫 “count” 的 state 变量
      const [count, setCount] = useState(0);
      // 声明多个 state 变量!
      const [age, setAge] = useState(42);
      const [fruit, setFruit] = useState('banana');
      const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
    

    2、使用 useEffect

    在熟悉 React class 的生命周期函数后,可以将 useEffect Hook 看做 componentDidMount componentDidUpdatecomponentWillUnmount 这三个函数的组合。与 componentDidMountcomponentDidUpdate 不同的是,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,使应用看起来响应更快。 大多数情况下,effect 不需要同步地执行。useEffect可以在函数组件中执行副作用操作(数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用)以下是分别是class组件/函数组件 例子:

    //class组件
    class Example extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count: 0
        };
      }
    
      componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
      }
      componentDidUpdate() {
        document.title = `You clicked ${this.state.count} times`;
      }
    
      render() {
        return (
          <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
              Click me
            </button>
          </div>
        );
      }
    }
    //函数组件
    import React, { useState, useEffect } from 'react';
    
    function Example() {
      const [count, setCount] = useState(0);
    
      // 与componentDidMount和componentDidUpdate类似:
      useEffect(() => {
        // 使用浏览器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 Hook 看做 componentDidMount componentDidUpdatecomponentWillUnmount 这三个函数的组合的写法如下:当返回一个函数时,即做了清除操作。更新逻辑不需要特定的代码来处理,因为 useEffect 默认就会处理,它会在调用一个新的 effect 之前对前一个 effect 进行清理。可使用多个effect,将不相关逻辑分离到不同的 effect 中,

    useEffect(() => {
        function handleStatusChange(status) {
          setIsOnline(status.isOnline);
        }
    
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        return () => { //清除操作
          ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });
    //性能优化
    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [count]); // 仅在 count 更改时更新
    

    3、使用useContext

    const value = useContext(MyContext);接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值,当前值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定,当组件上最近的<MyContext.Provider>更新时,useContext会触发重渲染,并使用最新值传递给 MyContext providercontext value 值,如以下示例:

    const themes = {
      light: {
        foreground: "#000000",
        background: "#eeeeee"
      },
      dark: {
        foreground: "#ffffff",
        background: "#222222"
      }
    };
    const ThemeContext = React.createContext(themes.light);
    function App() {
      return (
        <ThemeContext.Provider value={themes.dark}>
          <Toolbar />
        </ThemeContext.Provider>
      );
    }
    function Toolbar() {
      const theme = useContext(ThemeContext);
      return (
        <button style={{ background: theme.background, color: theme.foreground }}>
          I am styled by theme context!
        </button>
      );
    }
    

    4、使用useReducer

    const [state, dispatch] = useReducer(reducer, initialArg, init)useState的替代方案,当state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 时,useReducer 会比 useState 更适用,且使用 useReducer 还能给那些会触发深更新的组件做性能优化,以下是用 reducer 重写 useState 例子:

    function init(initialCount) {
      return {count: initialCount};
    }
    
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        case 'reset':
          return init(action.payload);
        default:
          throw new Error();
      }
    }
    
    function Counter({initialCount}) {
      const [state, dispatch] = useReducer(reducer, initialCount, init);
      //第三个参数,用作惰性初始化
      return (
        <>
          Count: {state.count}
          <button
            onClick={() => dispatch({type: 'reset', payload: initialCount})}>
            Reset
          </button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
        </>
      );
    }
    

    5、使用useCallback

    内联回调函数依赖项数组作为参数传入 useCallback,返回该函数的当前版本,该回调函数仅在某个依赖项改变时才会更新

    const memoizedCallback = useCallback(
      () => {
        doSomething(a, b);
      },
      [a, b],
    );
    

    6、使用useMemo

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])创建函数依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。传入 useMemo 的函数会在渲染期间执行,不要在这个函数内部执行与渲染无关的操作,如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值,可以把 useMemo 作为性能优化的手段,但不要把它当成语义上的保证,useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

    6、使用useRef

    const refContainer = useRef(initialValue)useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。将 ref 对象以 <div ref={myRef} /> 形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。useRef() 比 ref 属性更有用,它可以很方便地保存任何可变值,因为ref 属性创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: ...} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。

    function TextInputWithFocusButton() {
      const myRef = useRef(null); // null为初始值
      const onButtonClick = () => {
        // `current` 指向已挂载到 DOM 上的文本输入元素
        myRef.current.focus();
      };
      return (
        <>
          <input ref={myRef} type="text" />
          <button onClick={onButtonClick}>Focus the input</button>
        </>
      );
    }
    

    7、使用useImperativeHandle

    useImperativeHandle(ref, createHandle, [deps])useImperativeHandle 可以在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与forwardRef 一起使用:

    function FancyInput(props, ref) {
      const inputRef = useRef();
      useImperativeHandle(ref, () => ({
        focus: () => {
          inputRef.current.focus();
        }
      }));
      return <input ref={inputRef} ... />;
    }
    FancyInput = forwardRef(FancyInput);
    // 渲染 <FancyInput ref={inputRef} /> 的父组件可以调用 inputRef.current.focus()。
    

    8、使用useLayoutEffect

    9、使用useDebugValue

    useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。例如:一个返回 Date 值的自定义 Hook 可以通过格式化函数来避免不必要的 toDateString 函数调用: useDebugValue(date, date => date.toDateString());


    起源地下载网 » React Hooks的学习

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元