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 相当于生命周期 componentDidMount 、componentDidUpdate , useEffect 返回一个函数,清除副作用,相当于componentWillUnmount。
在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决
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 | ); |
实例查看 点击查看