[TOC]
### 1 為什么使用 React Hooks
對于一個新玩意(這也不算新玩意了)的使用肯定是有他的原因的撒,我們先來個簡單例子看看,現在我們做過超級超級簡單的例子:點擊按鈕數字增加1
先用我們原來的做法(用class的方式定義的組件)
~~~
import React, { Component } from 'react'
class Increased extends Component {
constructor (props) {
super (props)
this.state={count:0}
}
render() {
return (
<div>
<p>總數:{this.state.count}</p>
<button onClick={this.add.bind(this)}>增加</button>
</div>
)
}
add() {
this.setState({count:this.state.count+1})
}
}
export default Increased
~~~
咋們在來看看使用React Hooks做的
~~~
import React,{useState } from 'react'
const IncreasedHooks = () => {
const [ count , setCount ] =useState(0)//數組解構
return (
<div>
<p>總數:{count}</p>
<button onClick={()=>setCount(count+1)}>增加</button>
</div>
)
}
export default IncreasedHooks
~~~
下面是效果:
### 2 詳解 useState
useState是react自帶的一個hook函數,它的作用是用來聲明狀態變量。useState這個函數接收的參數是狀態的初始值,它返回一個數組,這個數組的第0位是當前的狀態值,第1位是可以改變狀態值的方法函數
如何聲明 根據上面的代碼就知道啦
const [ count , setCount ] =useState(0)//數組解構
如何讀取
因為返回的是個數組,按照取數組的元素的方式取就行了啦,讀取是很簡單的。只要使用{count}就可以,因為這時候的count就是JS里的一個變量,想在JSX中使用,值用加上{}就可以。
建議使用解構的方式,簡單快速,什么? 你不會解構? 那你戳這個吧解構賦值這些些你必須知道
~~~
<p>總數:{count}</p>
~~~
使用 改變state 我們就要使用返回的數組中的第二個值啦
~~~
<button onClick={()=>setCount(count+1)}>增加</button>
~~~
### 3 useEffect的使用
#### 3.1useEffect代替常用的生命周期函數
useEffect 可以用來代替我們常用的聲明周期函數 ,那我們一般什么時候使用生命周期函數呢,當然是我們在是做"副作用"的業務處理 代替了componentDidMount和componentDidUpdate。分別在組件第一次渲染后在瀏覽器控制臺打印出計數器結果和在每次計數器狀態發生變化后打印出結
使用useEffect時候有兩點需要注意的
React首次渲染和之后的每次渲染都會調用一遍useEffect函數,而之前我們要用兩個生命周期函數分別表示首次渲染(componentDidMonut)和更新導致的重新渲染(componentDidUpdate)。
useEffect中定義的函數的執行不會阻礙瀏覽器更新視圖,也就是說這些函數時異步執行的,而componentDidMonut和componentDidUpdate中的代碼都是同步執行的。個人認為這個有好處也有壞處吧,比如我們要根據頁面的大小,然后繪制當前彈出窗口的大小,如果時異步的就不好操作了。
~~~
const IncreasedHooks = () => {
const [ count , setCount ] =useState(0)
useEffect(()=>{
console.log(`useEffect=>You clicked ${count} times`)
})
//解決生命周期函數 代替了componentDidMount和componentDidUpdate。分別在組件第一次渲染后在瀏覽器控制臺打印出計數器結果和在每次計數器狀態發生變化后打印出結
return (
<div>
<div>使用React Hooks</div>
<p>總數:{count}</p>
<button onClick={()=>setCount(count+1)}>增加</button>
</div>
)
}
~~~
#### 3.2 實現類似componentWillUnmount(組件將要被卸載時執行)
使用路由實現組件的解綁,需要用到useEffect函數里面返回一個函數的形式,代替解綁生命周期函數 componentWillUnmount 組件將要被卸載時執行
~~~
const Index = () => {
useEffect(()=>{
console.log('useEffect=>老弟你來了!Index頁面')
return ()=>{
console.log('老弟,你走了!Index頁面')
}//返回一個函數的形式,代替解綁生命周期函數 componentWillUnmount 組件將要被卸載時執行
},[])
return <div>加油,程序員</div>
}
const List = () =>{
return (
<ul>
<li>你好</li>
<li>我好</li>
<li>他好</li>
</ul>
)
}
const IncreasedHooks = () => {
return (
<div>
<Router>
<ul>
<li><Link to = "/">首頁 </Link></li>
<li><Link to = "/list/">列表頁 </Link></li>
</ul>
<Route path ="/" exact component={Index}></Route>
<Route path ="/list/" component={List}></Route>
</Router>
</div>
)
}
~~~
其實這個主要是使用的useEffect的第二個參數,上面的程序中,不是用第二個參數的時候.每次狀態發生變化,useEffect都進行了解綁。真正實現主要是第二個人函數加了空數組.useEffect的第二個參數,它是一個數組,數組中可以寫入很多狀態對應的變量,意思是當狀態值發生變化時,我們才進行解綁。但是當傳空數組[]時,就是當組件將被銷毀時才進行解綁,這也就實現了componentWillUnmount的生命周期函數。
我的理解是:第二個參數是實現解綁條件
例如:給計數器也加上解綁:只需要在返回的數組中寫入記錄計數的狀態值count 變量
~~~
const IncreasedHooks = () => {
const [ count , setCount ] =useState(0)//數組解構
useEffect(()=>{
console.log(`useEffect=>You clicked ${count} times`)
return ()=>{
console.log('====================')
}
},[count])
return (
<div>
<p>總數:{count}</p>
<button onClick={()=>setCount(count+1)}>增加</button>
</div>
)
}
~~~
### 4 useContext的使用
useContext主要是用來實現父子組件之間的傳值 如下代碼實現
~~~
import React,{useState ,useContext, createContext } from 'react'
const CountContext = createContext()
// 定義子組件
const Coounter = () =>{
//子組件一句話就可以得到父組件傳遞過來的count
const count = useContext(CountContext)
return (<h2>{count}</h2>)
}
// 父組件
const IncreasedHooks2= () => {
const [ count , setCount ] =useState(0)
return (
<div>
<div>使用React Hooks</div>
<p>總數:{count}</p>
<button onClick={()=>setCount(count+1)}>增加</button>
{/* 父組件向組件提供值 */}
<CountContext.Provider value={count} >
<Coounter/>
</CountContext.Provider>
</div>
)
}
export default IncreasedHooks2
~~~
### 5 useReducer的使用
#### 5.1 useReducer時實現reducer
useContext 和useReducer 合作可以完成類似的Redux庫的操作,useReducer 可以讓代碼具有更好的可讀性和可維護性,它類似于Redux中的reducer,reducer這個函數接收兩個參數,一個是狀態,一個用來控制業務邏輯的判斷參數
一個簡單reducer的例子來理解什么是reducer
~~~
function countReducer(state, action) {
switch(action.type) {
case 'add':
return state + 1;
case 'sub':
return state - 1;
default:
return state;
}
}
~~~
使用useReducer
~~~
import React, { useReducer } from 'react';
const IncreasedHooks2 = () => {
const [count, dispatch] = useReducer((state, action) => {
switch (action) {
case 'add':
return state + 1
case 'sub':
return state - 1
default:
return state
}
}, 0)
return (
<div>
<h2>現在的分數是{count}</h2>
<button onClick={() => dispatch('add')}>Increment</button>
<button onClick={() => dispatch('sub')}>Decrement</button>
</div>
)
}
export default IncreasedHooks2
~~~
#### 5.2 useReducer useContext實現redux的狀態管理和狀態共享
實現狀態全局化并能統一管理,統一個事件的派發
案例:點擊按鈕切換對應的字體顏色
~~~
//父組件
import React from 'react';
import Buttons from './Buttons';
import ShowArea from './ShowArea'
import { Color } from './Color'; //引入Color組件
const ChangeColor = () => {
return (
<div>
<Color>
<Buttons />
<ShowArea />
</Color>
</div>
)
}
export default ChangeColor
~~~
~~~
//字體展示組件
import React,{useContext} from 'react'
import { ColorContext } from './Color';
const ShowArea = () => {
// 獲取color
const {color} = useContext(ColorContext)
return (
<div>
<div style={{color:color}}>字體顏色為{color}</div>
</div>
)
}
export default ShowArea
~~~
~~~
//按鈕組件
import React ,{useContext} from 'react';
import {ColorContext,UPDATE_COLOR} from './Color'
const Buttons = () => {
// 獲取共享的dispatch
const {dispatch} = useContext(ColorContext)
return (
<div>
{/* 使用dispatch派發一個action */}
<button onClick= {()=> {dispatch({type:UPDATE_COLOR,color:"red"})}}>紅色</button>
<button onClick= {()=> {dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黃色</button>
</div>
)
}
export default Buttons
~~~
~~~
//狀態管理
import React,{createContext ,useReducer } from 'react'
export const ColorContext = createContext()
export const UPDATE_COLOR = "UPDATE_COLOR"
// 定義reducer
const reducer = (state, action) => {
switch (action.type) {
case UPDATE_COLOR:
return action.color
default:
return state
}
}
// 顏色共享
export const Color = props => {
// 使用reducer
const [color, dispatch] = useReducer(reducer,'red')
return (
<div>
{/* 將color和dispatch共享出去 */}
<ColorContext.Provider value={{color,dispatch}}>
{props.children}
</ColorContext.Provider>
</div>
);
}
~~~
結果
### 6. useMemo
useMemo主要用來解決使用React hooks產生的無用渲染的性能問題,函數型組件沒有shouldCompnentUpdate(組件更新前觸發),我們就沒有辦法通過組件前的條件來決定組件是否更新.
且在函數組件中,也不再區分mount和update兩個狀態,這意味著函數組件的每一次調用都會執行內部的所有邏輯,就帶來了非常大的性能損耗。useMemo和useCallback都是解決上述性能問題的
~~~
import React , {useState,useMemo} from 'react';
function ComeHere(){
const [he, setHe] = useState('他在等著')
const [me, setMe] = useState('我在等著')
return (
<>
<button onClick={()=>{setHe(new Date().getTime())}}>他</button>
<button onClick={()=>{setMe(new Date().getTime()+',我走來了')}}>我</button>
<ChildComponent name={he}>{me}</ChildComponent>
</>
)
}
function ChildComponent({name,children}){
function changeHe(name){
console.log('她來了,她來了。他向我們走來了')
return name+',他向我們走來了'
}
//為了解決當我們點擊"我"按鈕時,"他"對應的changeHe方法不能執行,只有在點擊他按鈕時才能執行。才能減少子組件的多次沒有用的重新渲染
//其實只要使用useMemo,然后給她傳遞第二個參數,參數匹配成功,才會執行。
const actionHe = useMemo(()=>changeHe(name),[name])
return (
<>
<div>{actionHe }</div>
<div>{children}</div>
</>
)
}
~~~
### 7. useRef
用useRef獲取React JSX中的DOM元素,獲取后你就可以控制DOM的任何東西了。但是一般不建議這樣來作,React界面的變化可以通過狀態來控制。
用useRef來保存變量,這個在工作中也很少能用到,我們有了useContext這樣的保存其實意義不大
~~~
import React, { useRef} from 'react';
function Example(){
//聲明一個input的element
const inputEl = useRef(null)
const onButtonClick=()=>{
inputEl.current.value="Hello ,JSPang"
console.log(inputEl) //輸出獲取到的DOM節點
}
return (
<>
{/*保存input的ref到inputEl */}
<input ref={inputEl} type="text"/>
<button onClick = {onButtonClick}>在input上展示文字</button>
</>
)
}
export default Example
~~~
#### 8. 自定義Hooks函數
實例,自第一個實時監測瀏覽器窗口大小的Hooks函數
自定義Hooks函數,記住一定要用use開頭
~~~
import React,{ useState ,useEffect ,useCallback } from 'react';
const useWinSize = () =>{
const [size,setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})
//useCallback,目的是為了緩存方法(useMemo是為了緩存變量)
const onResize = useCallback(() => {
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
useEffect(()=>{
window.addEventListener('resize',onResize)
return ()=>{
window.removeEventListener('resize',onResize)
}
},[])
return size
}
//組件中使用
const MyHooks = ()=>{
const size = useWinSize()
return <div>size:{size.width}x{size.height}</div>
}
export default MyHooks
~~~
- 第一章 起步
- 第1節 創建react項目
- 第2節 hello world
- 第3節 數據綁定+事件處理
- 3.1 for循環事件處理中的傳參寫法、條件渲染
- 第4章 點擊切換文字
- 第5章 使用html寫react
- 第二章 運用
- 第1節 循環
- 第2節 實現一個簡單的TodoList
- 第2.1節 刪除
- 第3節 父子組件傳參
- 1. 父組件向子組件傳參
- 2. 子組件向父組件傳參
- 第4節 react-router實現一個簡單路由
- 第5節 生命周期
- 第6節 取數據
- 第 7節 獲取dom節點
- 第8節 雙向數據綁定
- 第三章 redux
- 第1節 介紹
- 第2節 安裝redux
- 第3節 使用
- 3.1 action
- 3.2 使用redux實現 todolist
- 第4節封裝redux中的action
- 第5節 redux-thunk中間件
- 5.1介紹
- 5.2使用
- 第四章 ant-design前端ui
- 第一節 安裝
- 第2節 使用
- 2.1 ant-design實現todoList增刪功能
- 第3節 使用整理
- 第五章 vue和react的比較
- 第六章 dva.js輕量級應用框架
- 第1節 介紹
- 第2節 安裝dva
- 第3節 頁面跳轉
- 1. 事件路由跳轉
- 2. 通過路由跳轉
- 第4節 組件之間通信
- 1. 父組件向子組件傳參
- 2. 子組件向父組件傳參
- 第5節 事件處理
- 第6節 發送請求
- 1. 通過路由判斷頁面渲染數據
- 2. 通過事件發送請求
- 第7節 運用
- 1. TodoList
- 1.添加數據
- 1.2輸入框敲回車觸發事件
- 2.刪除數據
- 3. 總結
- 第8節 配合antd使用
- 1. 引入antd
- 2.dva 使用antd注意事項
- 3. 知識點整理
- 第七章 dva后臺項目實戰
- 第1節 登錄加密
- 1.具體實現
- 第2節 知識點
- 第3節 樹結構
- 第八章 react新特性 hooks
- 第1節 hooks介紹
- 第2節 useState的使用
- 第3節 useEffect的使用
- 第4節 dva+antd+hooks企業后臺項目開發流程
- 第 5節 hooks 使用
- 運用
- 第6節 hook整理
- 第7節 react memo
- 第九章 react中使用Echarts
- 知識點
- react中使用mobx
- 知識點
- react中使用rem
- 遞歸實現目錄數
- react使用圖表
- react 同步更新策略
- antd tree默認展開無效
- ts中lint修復篇
- React-query方案
- 高階組件