isa*_*tan 19 javascript reactjs react-hooks
在带有钩子的React中,更新状态的正确方法是嵌套对象是什么?
export Example = () => {
const [exampleState, setExampleState] = useState(
{masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b"
fieldTwoTwo: "c"
}
}
})
Run Code Online (Sandbox Code Playgroud)
一个人怎么会使用setExampleState到的更新exampleState来a(附加一个字段)?
const a = {
masterField: {
fieldOne: "a",
fieldTwo: {
fieldTwoOne: "b",
fieldTwoTwo: "c"
}
},
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}
}
Run Code Online (Sandbox Code Playgroud)
b (改变价值)?
const b = {masterField: {
fieldOne: "e",
fieldTwo: {
fieldTwoOne: "f"
fieldTwoTwo: "g"
}
}
})
Run Code Online (Sandbox Code Playgroud)
Mah*_*rus 117
如果有人正在搜索 useState()挂钩更新对象
- Through Input
const [state, setState] = useState({ fName: "", lName: "" });
const handleChange = e => {
const { name, value } = e.target;
setState(prevState => ({
...prevState,
[name]: value
}));
};
<input
value={state.fName}
type="text"
onChange={handleChange}
name="fName"
/>
<input
value={state.lName}
type="text"
onChange={handleChange}
name="lName"
/>
***************************
- Through onSubmit or button click
setState(prevState => ({
...prevState,
fName: 'your updated value here'
}));
Run Code Online (Sandbox Code Playgroud)
Mic*_*ski 33
可以使用useReducerhook 来管理复杂状态,而不是useState. 为此,首先初始化状态并更新函数,如下所示:
const initialState = { name: "Bob", occupation: "builder" };
const [state, updateState] = useReducer(
(state, updates) => ({ ...state, ...updates }),
initialState
);
Run Code Online (Sandbox Code Playgroud)
然后您可以通过仅传递部分更新来更新状态,如下所示:
updateState({ occupation: "postman" })
Run Code Online (Sandbox Code Playgroud)
ase*_*rov 28
您可以像这样传递新值
setExampleState({...exampleState, masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}})
Run Code Online (Sandbox Code Playgroud)
Nis*_*hah 21
如果您正在寻找与this.setState(来自class components)相同的功能functional components,那么这个答案对您有很大帮助。
例如
您有如下所示的状态,并且只想从整个状态更新特定字段,那么您object destructing每次都需要使用,有时这会很烦人。
const [state, setState] = useState({first: 1, second: 2});
// results will be state = {first: 3} instead of {first: 3, second: 2}
setState({first: 3})
// To resolve that you need to use object destructing every time
// results will be state = {first: 3, second: 2}
setState(prev => ({...prev, first: 3}))
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我想出了这个useReducer方法。请检查useReducer。
const [state, setState] = useState({first: 1, second: 2});
// results will be state = {first: 3} instead of {first: 3, second: 2}
setState({first: 3})
// To resolve that you need to use object destructing every time
// results will be state = {first: 3, second: 2}
setState(prev => ({...prev, first: 3}))
Run Code Online (Sandbox Code Playgroud)
const [state, setState] = useReducer(stateReducer, {first: 1, second: 2});
// results will be state = {first: 3, second: 2}
setState({first: 3})
// you can also access the previous state callback if you want
// results will remain same, state = {first: 3, second: 2}
setState(prev => ({...prev, first: 3}))
Run Code Online (Sandbox Code Playgroud)
如果需要,您可以将其存储stateReducer在文件中并将其导入到每个文件中。utils
这是custom hook如果你想要的话。
import React from 'react';
export const stateReducer = (state, action) => ({
...state,
...(typeof action === 'function' ? action(state) : action),
});
const useReducer = (initial, lazyInitializer = null) => {
const [state, setState] = React.useReducer(stateReducer, initial, init =>
lazyInitializer ? lazyInitializer(init) : init
);
return [state, setState];
};
export default useReducer;
Run Code Online (Sandbox Code Playgroud)
打字稿
import React, { Dispatch } from "react";
type SetStateAction<S> = S | ((prev: S) => S);
type STATE<R> = [R, Dispatch<SetStateAction<Partial<R>>>];
const stateReducer = (state, action) => ({
...state,
...(typeof action === "function" ? action(state) : action),
});
const useReducer = <S>(initial, lazyInitializer = null): STATE<S> => {
const [state, setState] = React.useReducer(stateReducer, initial, (init) =>
lazyInitializer ? lazyInitializer(init) : init,
);
return [state, setState];
};
export default useReducer;
Run Code Online (Sandbox Code Playgroud)
小智 11
谢谢菲利普,这帮助了我 - 我的用例是我有一个包含很多输入字段的表单,所以我将初始状态保持为对象,但我无法更新对象状态。上面的帖子帮助了我:)
const [projectGroupDetails, setProjectGroupDetails] = useState({
"projectGroupId": "",
"projectGroup": "DDD",
"project-id": "",
"appd-ui": "",
"appd-node": ""
});
const inputGroupChangeHandler = (event) => {
setProjectGroupDetails((prevState) => ({
...prevState,
[event.target.id]: event.target.value
}));
}
<Input
id="projectGroupId"
labelText="Project Group Id"
value={projectGroupDetails.projectGroupId}
onChange={inputGroupChangeHandler}
/>
Run Code Online (Sandbox Code Playgroud)
Ily*_*nov 10
通常,您应该注意React状态下的深层嵌套对象。为避免意外行为,状态应不变地更新。当您拥有深层对象时,您最终会深层克隆它们以实现不变性,这在React中可能会非常昂贵。为什么?
深度克隆状态后,React将重新计算并重新呈现依赖于变量的所有内容,即使它们没有更改!
因此,在尝试解决问题之前,请先考虑如何使状态变平坦。这样做之后,您会发现漂亮的工具可以帮助处理大型状态,例如useReducer()。
如果您考虑过,但仍然确信需要使用深度嵌套的状态树,则仍可以将useState()与immutable.js和Immutability -helper之类的库一起使用。它们使更新或克隆深层对象变得简单,而不必担心可变性。
Ola*_*lip 10
我参加聚会迟到了.. :)
当目的是重新输入整个对象结构时,@aseferov 答案非常有效。但是,如果目标/目标是更新对象中的特定字段值,我相信下面的方法会更好。
情况:
const [infoData, setInfoData] = useState({
major: {
name: "John Doe",
age: "24",
sex: "M",
},
minor:{
id: 4,
collegeRegion: "south",
}
});
Run Code Online (Sandbox Code Playgroud)
更新特定记录将需要召回之前的状态 prevState
这里:
setInfoData((prevState) => ({
...prevState,
major: {
...prevState.major,
name: "Tan Long",
}
}));
Run Code Online (Sandbox Code Playgroud)
也许
setInfoData((prevState) => ({
...prevState,
major: {
...prevState.major,
name: "Tan Long",
},
minor: {
...prevState.minor,
collegeRegion: "northEast"
}));
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮助任何试图解决类似问题的人。
您必须使用 Rest 参数和展开语法(https://javascript.info/rest-parameters-spread)并设置一个带有 preState 的函数作为 setState 的参数。
不起作用(缺少功能)
[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState({
...state,
[key]: value
});
Run Code Online (Sandbox Code Playgroud)
有效!
[state, setState] = useState({})
const key = 'foo';
const value = 'bar';
setState(prevState => ({
...prevState,
[key]: value
}));
Run Code Online (Sandbox Code Playgroud)
追加和修改都可以通过一个简单的步骤完成。我认为这是更稳定和安全的,没有不可变或可变的依赖。
这是附加新对象的方法
setExampleState(prevState => ({
...prevState,
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}))
Run Code Online (Sandbox Code Playgroud)
假设您要再次修改masterField2对象。可能有两种情况。您想要更新整个对象或更新对象的特定键。
更新整个对象- 因此这里键masterField2的整个值将被更新。
setExampleState(prevState => ({
...prevState,
masterField2: {
fieldOne: "c",
fieldTwo: {
fieldTwoOne: "d",
fieldTwoTwo: "e"
}
},
}))
Run Code Online (Sandbox Code Playgroud)
但是,如果您只想更改masterField2对象内的fieldTwoOne键该怎么办?您执行以下操作。
let oldMasterField2 = exampleState.masterField2
oldMasterField2.fieldTwo.fieldTwoOne = 'changed';
setExampleState(prevState => ({
...prevState,
masterField2: oldMasterField2
}))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22270 次 |
| 最近记录: |