一、useState
react中文官網(wǎng)教程
1. 更新基本類型數(shù)據(jù)
在函數(shù)式組件中,可以使用 useState
這個 Hook 來定義和管理組件的狀態(tài)。useState
接受一個初始狀態(tài)作為參數(shù),并返回一個包含 state 和更新 state 的方法的數(shù)組。
下面是一個例子,展示了如何在函數(shù)式組件中定義自己的 state:
import React, { useState } from "react";
function MyComponent() {
// 定義一個名為 count 的 state 變量,并將初始值設(shè)置為 0
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increase Count</button>
</div>
);
}
export default MyComponent;
在上面的例子中,我們使用 useState
創(chuàng)建了一個名為 count
的狀態(tài)變量,并將其初始值設(shè)為 0。然后,我們將 count
的值展示在 <p>
元素中,并在按鈕的點(diǎn)擊事件中調(diào)用 setCount
來更新 count
的值。
每當(dāng)我們調(diào)用 setCount
來更新 count
的值時,React 會重新渲染組件并傳遞更新后的值給 count
。
2. 更新對象
在函數(shù)式組件中使用useState更新state中的對象可以通過以下步驟:
- 導(dǎo)入useState:
import React, { useState } from 'react';
- 創(chuàng)建一個對象作為初始狀態(tài)(state):
const initialState = { name: 'John', age: 30, email: 'john@example.com' };
- 在組件內(nèi)部使用useState鉤子聲明state:
const [person, setPerson] = useState(initialState);
這里person
是狀態(tài)對象,setPerson
是一個更新狀態(tài)的函數(shù)。useState(initialState)
是useState的初始值參數(shù)。
- 在組件中使用狀態(tài)對象:
return (
<div>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
<p>Email: {person.email}</p>
</div>
);
- 使用setPerson函數(shù)來更新狀態(tài)對象的值:
const updateEmail = () => {
setPerson({ ...person, email: 'updated@example.com' });
};
這里使用了ES6的展開語法(spread syntax)來復(fù)制現(xiàn)有的person對象,并更新email屬性的值。
- 在組件中調(diào)用updateEmail函數(shù)來更新狀態(tài):
<button onClick={updateEmail}>Update Email</button>
完整的示例代碼如下:
import React, { useState } from 'react';
const App = () => {
const initialState = { name: 'John', age: 30, email: 'john@example.com' };
const [person, setPerson] = useState(initialState);
const updateEmail = () => {
setPerson({ ...person, email: 'updated@example.com' });
};
return (
<div>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
<p>Email: {person.email}</p>
<button onClick={updateEmail}>Update Email</button>
</div>
);
};
export default App;
通過點(diǎn)擊"Update Email"按鈕,可以更新email屬性的值為"updated@example.com"。
在React的函數(shù)式組件中使用useState來更新一個對象的state時,有幾個注意點(diǎn)需要特別注意:
-
useState函數(shù)僅僅是按照傳入的初始值來初始化state,并不會合并對象。因此,在更新state時,需要先使用解構(gòu)方式取出舊的對象屬性值,然后再設(shè)置新的對象屬性值。
-
由于useState是按照值的變化來判斷是否重新渲染組件的,因此在更新state時,需要保證每一次更新都是返回一個新的對象。直接對原對象進(jìn)行修改并返回會導(dǎo)致state沒有發(fā)生變化,從而不會觸發(fā)重新渲染。
-
可以使用展開運(yùn)算符擴(kuò)展現(xiàn)有對象,再進(jìn)行屬性的更改。這樣可以確保每次都返回一個新的對象。
為什么要注意這些點(diǎn)呢?
首先,useState是基于值的比較來判斷是否重新渲染組件的,如果不注意每次都返回一個新的對象,可能會導(dǎo)致state沒有發(fā)生變化,從而不會觸發(fā)重新渲染,無法更新組件視圖。
其次,由于函數(shù)式組件沒有實(shí)例的概念,每次組件渲染都是獨(dú)立的,因此無法像類組件中使用this.setState那樣自動合并對象屬性。因此,在更新state時,需要手動合并舊的對象屬性值和新的對象屬性值,以確保不丟失任何舊的state屬性。
最后,使用展開運(yùn)算符擴(kuò)展對象的方式可以確保每次都返回一個全新的對象,這樣可以避免直接對原對象進(jìn)行修改而導(dǎo)致state沒有發(fā)生變化的問題。
3. 更新嵌套對象
在React的函數(shù)式組件中使用useState更新state中的嵌套對象,可以使用擴(kuò)展運(yùn)算符(spread operator)來實(shí)現(xiàn)。
舉例說明,假設(shè)有一個包含嵌套對象的state,如下所示:
const [state, setState] = useState({
name: "John",
age: 30,
address: {
street: "123 Main St",
city: "New York",
state: "NY"
}
});
要更新state中的嵌套對象,可以使用useState的setState函數(shù),傳遞一個新的對象,并使用擴(kuò)展運(yùn)算符將原有的state進(jìn)行展開,再覆蓋需要更新的屬性。例如,要更新address對象的city屬性,可以使用以下代碼:
setState({
...state,
address: {
...state.address,
city: "Los Angeles"
}
});
上面的代碼首先使用擴(kuò)展運(yùn)算符將原有的state展開,然后再針對需要更新的嵌套對象進(jìn)行展開,并更新特定的屬性。在本例中,我們更新了address對象的city屬性,將其值從"New York"更新為"Los Angeles"。
完整的示例代碼如下所示:
import React, { useState } from "react";
function App() {
const [state, setState] = useState({
name: "John",
age: 30,
address: {
street: "123 Main St",
city: "New York",
state: "NY"
}
});
const updateCity = () => {
setState({
...state,
address: {
...state.address,
city: "Los Angeles"
}
});
};
return (
<div>
<p>Name: {state.name}</p>
<p>Age: {state.age}</p>
<p>Street: {state.address.street}</p>
<p>City: {state.address.city}</p>
<p>State: {state.address.state}</p>
<button onClick={updateCity}>Update City</button>
</div>
);
}
export default App;
在上述示例中,我們首先使用useState定義了包含嵌套對象的state,然后在組件中顯示了state中的屬性。最后,我們使用一個按鈕來調(diào)用updateCity函數(shù),該函數(shù)會更新state中的嵌套對象。點(diǎn)擊按鈕后,更新后的city屬性值將顯示為"Los Angeles"。
4. 更新數(shù)組
在函數(shù)式組件中使用useState
來更新state中的數(shù)組,可以通過結(jié)構(gòu)賦值的方式獲取數(shù)組和更新數(shù)組的函數(shù)。一般情況下,使用useState
更新數(shù)組時需要注意以下幾點(diǎn):
-
為了保持state的不可變性,應(yīng)該使用數(shù)組的展開運(yùn)算符(spread operator)來創(chuàng)建一個新的數(shù)組。
-
當(dāng)更新數(shù)組時,需要將要更新的元素和其余元素區(qū)分開來。通常使用
Array.map
函數(shù)來遍歷數(shù)組,并找到要更新的元素。 -
可以使用
Array.filter
函數(shù)過濾數(shù)組中的元素,從而可以刪除特定的元素。 -
注意在更新數(shù)組時,在判斷相等性時使用嚴(yán)格相等運(yùn)算符
(===)
,而不是用“淺比較”運(yùn)算符(==)
。
下面是一個更新數(shù)組的例子:
import React, { useState } from "react";
function Example() {
const [list, setList] = useState([1, 2, 3, 4, 5]);
const handleUpdate = () => {
// 通過展開運(yùn)算符創(chuàng)建一個新的數(shù)組,并更新數(shù)組的第一個元素
setList([...list.slice(0, 1), 100, ...list.slice(2)]);
};
const handleDelete = (item) => {
// 使用filter過濾數(shù)組,刪除特定的元素
setList(list.filter((el) => el !== item));
};
return (
<div>
<ul>
{list.map((item) => (
<li key={item}>
{item}
<button onClick={() => handleDelete(item)}>刪除</button>
</li>
))}
</ul>
<button onClick={handleUpdate}>更新</button>
</div>
);
}
export default Example;
在這個例子中,list
是一個包含數(shù)字的數(shù)組。點(diǎn)擊列表項(xiàng)后的“刪除”按鈕會刪除相應(yīng)的元素,點(diǎn)擊“更新”按鈕會將數(shù)組的第一個元素更新為100。每次更新數(shù)組時,使用展開運(yùn)算符創(chuàng)建一個新的數(shù)組,并把更新的元素插入到適當(dāng)?shù)奈恢?,這樣可以保持state的不可變性。在刪除元素時,使用filter
函數(shù)過濾掉特定的元素。
5.更新數(shù)組對象
在函數(shù)式組件中使用 useState
來更新 state 數(shù)組中的內(nèi)部對象,可以使用解構(gòu)賦值的方式來獲取數(shù)組中的指定對象,并使用 useState
來更新該對象的屬性。
首先,在函數(shù)式組件中使用 useState
定義一個狀態(tài)變量,可以設(shè)置初始狀態(tài)為一個包含內(nèi)部對象的數(shù)組。例如,使用以下代碼定義一個狀態(tài)變量 items
,并設(shè)置初始狀態(tài)為一個包含兩個內(nèi)部對象的數(shù)組:
const [items, setItems] = useState([
{ name: "apple", quantity: 1 },
{ name: "banana", quantity: 2 }
]);
然后,通過解構(gòu)賦值的方式獲取數(shù)組中的指定對象,并使用 useState
更新該對象的屬性。例如,通過以下代碼獲取數(shù)組中的第一個對象 item
并更新其 name
屬性:
const [item, setItem] = useState(items[0]);
const handleChangeName = () => {
setItem(prevItem => ({ ...prevItem, name: "orange" }));
};
在上述代碼中,setItem
函數(shù)通過接收一個回調(diào)函數(shù)來更新 item
對象的屬性。該回調(diào)函數(shù)使用展開運(yùn)算符 ...
將之前的屬性拷貝到一個新的對象中,并更新 name
屬性為 "orange"
。
需要注意的是,在更新數(shù)組時,不能直接修改數(shù)組中的對象。要更新數(shù)組中的對象,需要先拷貝數(shù)組,然后再更新其中的對象??梢允褂?Array.map()
方法來拷貝數(shù)組并更新其中的對象。例如,使用以下代碼將數(shù)組中的第一個對象的 name
屬性改為 "orange"
:
const updatedItems = items.map((item, index) => {
if (index === 0) {
return { ...item, name: "orange" };
}
return item;
});
setItems(updatedItems);
上述代碼中,Array.map()
方法遍歷數(shù)組,當(dāng)索引為 0 的時候,返回一個新的對象,并更新其 name
屬性為 "orange"
;否則,返回原來的對象。然后,將得到的新數(shù)組 updatedItems
設(shè)置為新的狀態(tài)值。
二、Immer
1. 什么是Immer
Immer是一個JavaScript庫,用于管理不可變狀態(tài)。它通過基于原始狀態(tài)創(chuàng)建一個新的狀態(tài)樹來實(shí)現(xiàn)不可變性。它提供了一種簡單而直觀的方式來處理復(fù)雜的狀態(tài)更新邏輯,使代碼更易于理解和維護(hù)。Immer可以與任何JavaScript框架或庫一起使用,并且對于處理大型數(shù)據(jù)結(jié)構(gòu)和深層嵌套的對象非常有用。它是一個流行的工具,用于管理JavaScript應(yīng)用程序中的狀態(tài)。
在React的函數(shù)式組件中,推薦使用Immer來處理復(fù)雜的數(shù)據(jù)state,特別是深層嵌套的數(shù)組對象,有以下幾個原因:
-
操作不可變數(shù)據(jù)更加方便:Immer提供了一種簡潔的方式來直接對不可變數(shù)據(jù)進(jìn)行修改。通過使用Immer的produce函數(shù),可以在不直接修改原始數(shù)據(jù)的情況下,創(chuàng)建一個可變的草稿副本,并且在草稿上進(jìn)行所有的更改操作。這樣可以避免因?yàn)橹苯有薷脑紨?shù)據(jù)而導(dǎo)致的引用問題和副作用問題。
-
性能優(yōu)化:Immer采用了一種優(yōu)化技術(shù),稱為“結(jié)構(gòu)共享”,它能夠在不實(shí)際復(fù)制數(shù)據(jù)的情況下實(shí)現(xiàn)不可變數(shù)據(jù)的修改。這種技術(shù)可以大大提高性能,特別是對于大型、深層嵌套的數(shù)據(jù)結(jié)構(gòu)。
-
減少模板嵌套深度:在處理深層嵌套的數(shù)組對象時,使用Immer可以減少模板嵌套的深度。因?yàn)镮mmer提供了一種更簡潔、更直觀的方式來修改深層嵌套的數(shù)據(jù),這能夠提高代碼的可讀性和可維護(hù)性。
總之,使用Immer可以幫助我們更方便地處理復(fù)雜的數(shù)據(jù)state,尤其是深層嵌套的數(shù)組對象。它簡化了對不可變數(shù)據(jù)的操作,并提供了性能優(yōu)化的機(jī)制,使得我們能夠更加高效地開發(fā)React應(yīng)用。
2. 使用use-immer更新嵌套對象
在React的函數(shù)式組件中,可以使用use-immer庫來更新嵌套對象的state。use-immer是基于Immer庫的React Hook封裝,它可以方便地進(jìn)行不可變狀態(tài)更新。
以下是一個示例,展示如何使用use-immer更新嵌套對象的state:
首先,安裝use-immer庫:
npm install use-immer
然后,導(dǎo)入useImmer函數(shù)并在函數(shù)式組件中使用它:
import React, { useState } from 'react';
import { useImmer } from 'use-immer';
function App() {
const [state, setState] = useImmer({
user: {
name: 'John',
age: 25
}
});
// 更新嵌套對象的示例函數(shù)
const updateUserName = () => {
setState(draft => {
draft.user.name = 'Tom';
});
};
return (
<div>
<h1>{state.user.name}</h1>
<p>{state.user.age}</p>
<button onClick={updateUserName}>Update Name</button>
</div>
);
}
export default App;
在上面的示例中,我們使用useState和useImmer來聲明和初始化state。state是一個嵌套對象,包含一個user對象。然后,我們在updateUserName函數(shù)中使用setState函數(shù)來更新嵌套對象的state。在setState的回調(diào)函數(shù)中,我們可以使用draft參數(shù)來修改狀態(tài)。
使用use-immer庫的好處是,我們可以在回調(diào)函數(shù)中直接修改draft對象,就像在原始狀態(tài)上進(jìn)行修改一樣。useImmer會負(fù)責(zé)處理不可變性,最終生成一個新的狀態(tài),并將其應(yīng)用于組件。
以上是使用use-immer庫在React的函數(shù)式組件中更新嵌套對象狀態(tài)的示例??梢愿鶕?jù)實(shí)際需求進(jìn)行相應(yīng)的修改和擴(kuò)展。
3. 使用useImmer更新數(shù)組內(nèi)部的對象
可以使用useImmer hook結(jié)合immer來更新函數(shù)式組件中數(shù)組內(nèi)部的對象。useImmer hook是在React中使用Immer庫的推薦方式。
以下是一個示例,說明如何使用useImmer更新數(shù)組內(nèi)部的對象:
import React, { useState } from 'react';
import { useImmer } from 'use-immer';
const MyComponent = () => {
// 使用useState hook創(chuàng)建數(shù)組狀態(tài)
const [data, setData] = useState([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 3, name: 'Bob' },
]);
// 使用useImmer hook創(chuàng)建可變的數(shù)據(jù)副本draft和更新函數(shù)setDraft
const [draft, setDraft] = useImmer(data);
// 更新對象的名稱
const updateName = (id, name) => {
setDraft(draft => {
// 使用immer的produce函數(shù)來更新draft
const item = draft.find(item => item.id === id);
if (item) {
item.name = name;
}
});
};
return (
<div>
{draft.map(item => (
<div key={item.id}>
<span>{item.name}</span>
{/* 在組件中觸發(fā)更新名稱的函數(shù) */}
<button onClick={() => updateName(item.id, 'Updated Name')}>
Update Name
</button>
</div>
))}
</div>
);
};
export default MyComponent;
在上面的代碼中,我們首先使用useState hook創(chuàng)建了一個數(shù)組狀態(tài)data,然后使用useImmer hook創(chuàng)建了一個可變的數(shù)據(jù)副本draft和一個更新函數(shù)setDraft。在更新函數(shù)中,我們使用immer的produce函數(shù)來更新draft,修改特定ID對應(yīng)的對象的名稱。
在組件的返回值中,我們使用draft.map循環(huán)遍歷數(shù)組內(nèi)部的對象,顯示每個對象的名稱,并使用按鈕來觸發(fā)更新的函數(shù)。文章來源:http://www.zghlxwxcb.cn/news/detail-724679.html
當(dāng)你點(diǎn)擊"Update Name"按鈕時,會更新draft中特定ID對應(yīng)的對象的名稱,由于draft是可變的,所以React會自動更新組件的渲染。文章來源地址http://www.zghlxwxcb.cn/news/detail-724679.html
到了這里,關(guān)于react中的useState和useImmer的用法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!