官网 https://react.docschina.org/docs/hooks-intro.html

有状态组件和无状态组件

react-hooks快速上手 - 图1
在无状态组件里

  • 没有状态
  • 没有生命周期
  • 没有this

这就注定,我们所推崇的函数组件,只能做UI展示的功能,涉及到状态的管理与切换,我们不得不用类组件或者redux。
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性(声明周期等)。

启动一个react项目

npx create-react-app my-app cd my-app npm start

一个计数器组件

  1. import React from 'react';
  2. class Example extends React.Component {
  3. constructor(props) {
  4. super(props);
  5. this.state = {
  6. count: 0
  7. };
  8. }
  9. render() {
  10. return (
  11. <div>
  12. <p>You clicked {this.state.count} times</p>
  13. <button onClick={() => this.setState({ count: this.state.count + 1 })}>
  14. Click me
  15. </button>
  16. </div>
  17. );
  18. }
  19. }
  20. export default Example;


useState

纯函数组件没有状态,State Hooks 用于为函数组件引入状态

声明

https://react.docschina.org/docs/hooks-state.html#declaring-a-state-variable

使用

https://react.docschina.org/docs/hooks-state.html#reading-state

使用多个state

https://react.docschina.org/docs/hooks-state.html#tip-using-multiple-state-variables

更新state

https://react.docschina.org/docs/hooks-state.html#updating-state

用State Hooks重写上边的计数器函数

import React, { useState, useEffect } from 'react';

const Example = () => {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      // 更新count
      <button onClick={() => setCount(count + 1)}>
        Click me
       </button>
    </div>
  );
}

export default Example;

你之前可能把它们叫做“无状态组件”。但现在我们为它们引入了使用 React state 的能力,所以我们更喜欢叫它”函数组件”。

useEffect

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

// 类组件

import React from 'react';

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

  componentDidMount() {
    document.title = `You  ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You  ${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>
    );
  }
}

export default Example;

// 函数组件

import React, { useState, useEffect } from 'react';

const Example = () => {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You ${count} times`;
  });


  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
       </button>
    </div>
  );
}

export default Example;

实现comonentDidMounted
https://segmentfault.com/q/1010000017570341

useContext

使用

https://react.docschina.org/docs/hooks-reference.html#usecontext

import React, { useState, useEffect, useContext } from 'react';

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);
console.log(ThemeContext, "--ThemeContext--")
function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  /**
   * 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
   * 当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。
   * 
   * 当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,
   * 并使用最新传递给 MyContext provider 的 context value 值。
   */
  const theme = useContext(ThemeContext);
  console.log(theme, "===")
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

export default App;

useReducer

参考

https://www.jianshu.com/p/7e778adec7d1

我们知道,在使用React的过程中,如遇到状态管理,我们一般会用到Redux,而React本身是不提供状态管理的。而useReducer()为我们提供了状态管理。首先,关于redux我们都知道,其原理是我们通过用户在页面中发起action,从而通过reducer方法来改变state,从而实现页面和状态的通信。而Reducer的形式是(state, action) => newstate。类似,我们的useReducer()是这样的。

const [state, dispatch] = useReducer(reducer, initialState)

它接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数。下面我们依然用来实现一个计数器。

和redux一样,我们是需要通过页面组件发起action来调用reducer方法,从而改变状态,达到改变页面UI的这样一个过程。所以我们会先写一个Reducer函数,然后通过useReducer()返回给我们的state和dispatch来驱动这个数据流。思路就是这样,下面我们上代码

import React, { useReducer } from 'react'

const App = () => {
  // reducer
  const reducer = (state, action) => {
    if (action.type === 'add') {
      return {
        ...state,
        count: state.count + 1,
      }
    } else {
      return state
    }
  }

  const addcount = () => {
    // 派发action
    dispatch({
      type: 'add'
    })
  }

  /**
   * 它接受reducer函数和状态的初始值作为参数,返回一个数组,
   * 其中
   * 第一项为当前的状态值
   * 第二项为发送action的dispatch函数。
   */
  const [state, dispatch] = useReducer(reducer, { count: 0 })

  return (
    <>
      <p>{state.count}</p>
      <button onClick={addcount}>count++</button>
    </>
  )
}

export default App