zoukankan      html  css  js  c++  java
  • React Hooks

    官网:https://zh-hans.reactjs.org/docs/hooks-state.html#gatsby-focus-wrapper

    Hook 是什么? 

      Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

      Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你在 React 函数组件中添加 state 的 Hook。稍后我们将学习其他 Hook。

    什么时候我会用 Hook? 

      如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其转化为 class。现在你可以在现有的函数组件中使用 Hook。

    使用Hook的限制:

    • 只能写在函数组件和自定义Hook
    • 不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们

    一、useState

      1.声明

      以往在class中声明一个变量count

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

      使用useState声明一个count

    import React, { useState } from 'react';
    
    function Example() {
        // 声明一个叫 “count” 的 state 变量
        const [count, setCount] = useState(0);

      const [count, setCount] = useState(0);

      count:自定义state变量名,这里等同于this.state.count

      setCount:自定义函数名,等同于this.setSate

      useState只有一个参数,即为count的初始值,这里意为count初始值为0

      2.读取

      class

    <p>You clicked {this.state.count} times</p>

      函数

    <p>You clicked {count} times</p>

      3.更新

      class

      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        Click me
      </button>
    

      函数

      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>

    二、useEffect

      Effect Hook 可以让你在函数组件中执行副作用操作

      如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdate 和 componentWillUnmount 这三个函数的组合。

      1.使用

    import React, { useState, useEffect } from 'react';
    
    function Example() {
        const [count, setCount] = useState(0);
        // 异步,第一次渲染和每次更新完毕后执行 Effect 内操作
        useEffect(() => {
            console.log(`You clicked ${count} times`)
        });
    
        return (
            <div>
                <p>You clicked {count} times</p>
                <button onClick={() => setCount(count + 1)}>
                    Click me
                </button>
            </div>
        );
    }

      2.清除

      React 何时清除 effect? React 会在组件卸载的时候执行清除操作。

      effect 在每次渲染的时候都会执行,所以 React 在执行当前 effect 之前对上一个 effect 进行清除。

      effect 如果返回一个函数,React 将会在执行清除操作时调用它

        useEffect(() => {
            console.log(`You clicked ${count} times`)
            return function(){
                console.log('清除 effect')
            }
        });

      3.跳过 Effect 进行性能优化

        useEffect(() => {
            console.log(`You clicked ${count} times`)
            return function(){
                console.log('清除 effect')
            }
        }, [count]); // 仅在 count 更改时更新

      如果数组中有多个元素,即使只有一个元素发生变化,React 也会执行 effect
      如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([]

      如果你传入了一个空数组([]),effect 内部的 props 和 state 就会一直拥有其初始值

    三、useContext

      Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性

    import React, { createContext, useContext } from 'react';
    
    const themes = {
        light: {
            foreground: "#000000",
            background: "#eeeeee"
        },
        dark: {
            foreground: "#ffffff",
            background: "#222222"
        }
    };
    // 通过createContext在组件外创建 Context 对象,createContext(defaultValue)
    // 使用 Context 对象的组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值
    // 只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效
    const ThemeContext = createContext(themes.light);
    
    function App() {
        return (
            // ThemeContext.Provider提供了一个Context对象,这个对象是可以被子组件共享的。
            <ThemeContext.Provider value={themes.dark}>
                {/* Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据 */}
                {/* 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染 */}
                <Toolbar />
            </ThemeContext.Provider>
        );
    }
    
    // 中间的组件再也不必指明往下传递 theme 了。
    function Toolbar(props) {
        return (
            <div>
                <ThemedButton />
            </div>
        );
    }
    
    function ThemedButton() {
        // useContext 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值
        // useContext 的参数必须是 context 对象本身
        const theme = useContext(ThemeContext);
        // 当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定
        return (
            <button style={{ background: theme.background, color: theme.foreground }}>
                I am styled by theme context!
            </button>
        );
    }

     四、useReducer(可以先熟悉 Redux )

    // 指定初始state
    const [state, dispatch] = useReducer(reducer, {count: initialCount});
    const [参数名,dispatch]= useReducer(reducer, 初始值);
    // 惰性初始化
    const [state, dispatch] = useReducer(reducer, initialArg, init);
    const [参数名,dispatch]= useReducer(reducer, 初始函数传入值, init初始函数);

      useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

    // 计数器示例
    import React, { useReducer } from 'react';
    
    // init函数
    function init(initialCount) {
        return { count: initialCount };
    }
    
    // reducer
    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() {
        // useReducer(reducer, 传入init的初始值, init)
        const [state, dispatch] = useReducer(reducer, 0, init);
        return (
            <>
                Count: {state.count}
                <button
                    onClick={() => dispatch({ type: 'reset', payload: 0 })}>
                    Reset
            </button>
                <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
                <button onClick={() => dispatch({ type: 'increment' })}>+</button>
            </>
        );
    }

    五、useRef

      useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

    // 示例:输入框聚焦
    import React, { useRef } from 'react';
    
    function TextInputWithFocusButton() {
        const inputEl = useRef(null);
        const onButtonClick = () => {
            // `current` 指向已挂载到 DOM 上的文本输入元素
            inputEl.current.focus();
        };
        return (
            <>
                <input ref={inputEl} type="text" />
                <button onClick={onButtonClick}>Focus the input</button>
            </>
        );
    }

      useRef() 和自建一个 {current: ...} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象

      当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

    六、自定义Hook

      自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook

      共享逻辑,代码封装

      自定义useReducer示例:

    import React, { useState } from 'react';
    
    // 自定义 useReducer ,命名用 "use"
    function useReducer(reducer, initialState) {
        const [state, setState] = useState(initialState);
    
        function dispatch(action) {
            const nextState = reducer(state, action);
            setState(nextState);
        }
    
        // 返回state 和 dispatch
        return [state, dispatch];
    }
    
    // reducer 规则
    function reducer(state, action) {
        switch (action.type) {
            case 'increment':
                return state + 1;
            case 'decrement':
                return state - 1;
            default:
                throw new Error();
        }
    }
    
    function App() {
        // 使用自定义 Hook
        const [state, dispatch] = useReducer(reducer, 0);
    
        function handleIncrement() {
            dispatch({ type: 'increment' });
        }
    
        function handleDecrement() {
            dispatch({ type: 'decrement' });
        }
        return (
            <div>
                {state}
                <button onClick={() => handleIncrement()}>按钮+</button>
                <button onClick={() => handleDecrement()}>按钮-</button>
            </div>
        )
    }

     

  • 相关阅读:
    C# Redis实战(四)
    C# Redis实战(三)
    C# Redis实战(二)
    C# Redis实战(一)
    C#连接内存数据库redis【1、Redis存读取数据】
    C#连接内存数据库redis【1、安装配置】
    c#根据配置文件反射
    内存数据库:Redis与Memcached的区别
    内存数据库:memcached与redis技术的对比试验
    【转】【涨姿势】支付宝怎么做风险控制?
  • 原文地址:https://www.cnblogs.com/jing-zhe/p/14557497.html
Copyright © 2011-2022 走看看