React Hooks 入门

React Hooks 是 React v16.8 版本引入了全新的 API。

React Hooks 基本概念

React 默认提供的四个最常用的钩子

  • useState()
  • useEffect()
  • useContext()
  • useReducer()

useState()

useState()用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。

先看这个例子,这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加。

1
import React, { useState } from 'react';
2
3
function App() {
4
  const [count, setCount] = useState(0);
5
6
  return (
7
    <div>
8
      <p>You clicked {count} times</p>
9
      <button onClick={() => setCount(count + 1)}>
10
        Click me
11
      </button>
12
    </div>
13
  );
14
}

实例查看 点击查看

useEffect()

useEffect()用来引入具有副作用的操作,最常见的就是向服务器请求数据。

1
import React, { useState, useEffect } from "react";
2
import "./styles.css";
3
4
function App() {
5
  const [count, setCount] = useState(0);
6
7
  useEffect(() => {
8
    document.title = `You clicked ${count} times`;
9
  });
10
11
  return (
12
    <div>
13
      <p>You clicked {count} times</p>
14
      <button onClick={() => setCount(count + 1)}>Click me</button>
15
    </div>
16
  );
17
}
18
19
export default App;

实例查看 点击查看

上面例子可以看出 useEffect 相当于生命周期 componentDidMountcomponentDidUpdate , useEffect 返回一个函数,清除副作用,相当于componentWillUnmount

在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevPropsprevState 的比较逻辑解决

1
componentDidUpdate(prevProps, prevState) {
2
  if (prevState.count !== this.state.count) {
3
    document.title = `You clicked ${this.state.count} times`;
4
  }
5
}

函数组件中,只要传递数组作为 useEffect 的第二个可选参数即可:

1
useEffect(() => {
2
  document.title = `You clicked ${count} times`;
3
}, [count]); // 仅在 count 更改时更新

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。

useContext()

如果需要在组件之间共享状态,可以使用useContext()

现在有两个组件 Navbar 和 Messages,我们希望它们之间共享状态。

第一步就是使用 React Context API,在组件外部建立一个 Context。

1
const AppContext = React.createContext();

组件封装代码如下

1
<AppContext.Provider value={{
2
  username: 'react useContent'
3
}}>
4
  <div className="App">
5
    <Navbar/>
6
    <Message/>
7
  </div>
8
</AppContext.Provider>

AppContext.Provider提供了一个 Context 对象,这个对象可以被子组件共享。

Navbar 组件的代码如下

1
const Navbar = () => {
2
  const { username } = useContext(AppContext);
3
  return (
4
    <div className="navbar">
5
      <p>{username}</p>
6
    </div>
7
  );
8
}

Message 组件的代码如下

1
const Message = () => {
2
  const { username } = useContext(AppContext);
3
  return (
4
    <div className="message">
5
      <p>{username}</p>
6
    </div>
7
  );
8
}

实例查看 点击查看

useReducer()

useReducers()钩子用来引入 Reducer 功能。

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

useReducer 接受 Reducer 函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action 的dispatch函数。

下面是一个计数器的例子。用于计算状态的 Reducer 函数如下。

1
const reducer = (state, action) => {
2
  switch (action.type) {
3
    case actions.INCREMENT:
4
      return {
5
        ...state,
6
        count: state.count + 1
7
      };
8
    case actions.DECREMENT:
9
      return {
10
        ...state,
11
        count: state.count - 1
12
      };
13
    default:
14
      return state;
15
  }
16
};

组件代码如下

1
const [state, dispatch] = useReducer(reducer, { count: 1 });
2
 return (
3
   <div className="App">
4
     <p>{state.count}</p>
5
     <button onClick={() => dispatch({ type: actions.INCREMENT })}>+1</button>
6
     <button onClick={() => dispatch({ type: actions.DECREMENT })}>-1</button>
7
   </div>
8
 );

实例查看 点击查看