英文:
Easier way to add an object to the current state
问题
以下是您要翻译的内容:
"有人能解释一下为什么这是在React中将对象添加到状态的接受标准吗?因为我似乎找不到我要找的答案。
const [artists, setArtists] = useState([]);
setArtists([
...artists,
{ id: nextId++, name: name }
]);
我觉得应该有一种更简单的方法来做这件事,而不是artists.push()
,React文档说这是不好的,因为应该将状态视为不可变的,而不是将旧状态与新状态合并。
类似于zustand
状态管理在文档中的示例:
“set函数用于更新存储中的状态。由于状态是不可变的,它应该像这样:
set((state) => ({ ...state, count: state.count + 1 }))
“然而,由于这是一个常见的模式,set实际上会合并状态,因此我们可以跳过...state
部分:
set((state) => ({ count: state.count + 1 }))
也许我漏掉了什么,但您能解释一种更好/更简单的方法,或者为什么这是被接受的标准,而没有更简单的方法可能存在吗?"
英文:
Can someone explain to me why this is the accepted standard for adding to an object to the state in react as I can't seem to find the answer I'm looking for.
const [artists, setArtists] = useState([]);
setArtists([
...artists,
{ id: nextId++, name: name }
]);
I feel like there should be a much easier way to do this other than artists.push()
which the react docs say is bad as you should treat the state as immutable instead of having to combine the old state with the new.
Similar to how zustand
state management works in the docs where it shows:
"The set function is to update state in the store. Because the state is immutable, it should have been like this:"
set((state) => ({ ...state, count: state.count + 1 }))
"However, as this is a common pattern, set actually merges state, and we can skip the ...state part:"
set((state) => ({ count: state.count + 1 }))
Maybe I'm missing something, but could you explain a better/easier way for doing this or why this is the accepted standard and nothing easier can possibly exist?
答案1
得分: 1
React 需要检查组件何时需要更新,即重新渲染。
为了做到这一点,React 在状态更新之前和之后比较属性和状态。与简单地假定对象不会改变相比,比较整个对象要复杂得多。因此,如果您想要更改对象的状态并传入一个新对象而不是已操作的旧对象,React 立即知道需要重新渲染。
在 React 中,状态更新函数(例如,你的示例中的 setArtists)用你传递给它的内容替换当前状态。它不会将新状态与旧状态合并。
这种状态管理上的明确性为您提供了更多的控制,但也意味着您必须手动将先前的状态与新状态合并,这可能有点冗长,特别是在向数组添加元素或更新对象属性时。
其他状态管理库提供了更简单的合并机制,因为它们设计用于处理复杂的状态管理并尝试简化这些类型的操作。但它们添加了一层抽象,这可能并不总是必要的,特别是对于较简单的应用程序。React 更喜欢提供原语并让您根据需要构建自己的抽象。
当然,如果需要,您也可以编写自己的自定义钩子,以适当地实现这些操作,以避免在各个组件中的开销。对于数组,它可能看起来像这样:
import { useState } from 'react';
function useArray(initialArray) {
const [array, setArray] = useState(initialArray);
function push(element) {
setArray(prev => [...prev, element]);
}
function remove(index) {
setArray(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]);
}
function clear() {
setArray([]);
}
return { array, push, remove, clear };
}
export default useArray;
要使用它:
import useArray from './useArray';
function App() {
const artists = useArray([]);
let nextId = 1;
function addArtist(name) {
artists.push({ id: nextId++, name: name });
}
// 其他操作
}
也许这种解决方法对您来说更熟悉,因为它与状态处理类似,而且在我看来更可读。
英文:
React needs to check when a component needs to be updated, i.e. rendered.
To do this, react compares the props and the state before and after the state update. Comparing whole objects is much more complex than simply assuming that objects don't change. So if you want to change the state of an object and pass in a new object instead of the manipulated old object, react knows immediately that something needs to be re-rendered.
In React, the state update function (e.g., setArtists in your example) replaces the current state with whatever you pass to it. It doesn't merge the new state with the old state.
This explicitness in state management gives you more control but also means you have to manually merge the previous state with the new state, which can be a bit verbose, especially when adding to an array or updating an object property.
Other state management libraries provide a more straightforward merging mechanism because they are designed to handle complex state management and try to simplify these kinds of operations. But they add a layer of abstraction which might not always be necessary, especially for simpler apps. React prefers to give you the primitives and let you build your abstractions as you need them.
Of course, you could also write your own hook that implements the operations appropriately, if necessary, to avoid the overhead in the individual components. For arrays it could look like this
import { useState } from 'react';
function useArray(initialArray) {
const [array, setArray] = useState(initialArray);
function push(element) {
setArray(prev => [...prev, element]);
}
function remove(index) {
setArray(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]);
}
function clear() {
setArray([]);
}
return { array, push, remove, clear };
}
export default useArray;
to use it
import useArray from './useArray';
function App() {
const artists = useArray([]);
let nextId = 1;
function addArtist(name) {
artists.push({ id: nextId++, name: name });
}
}
Maybe this workaround is more familiar to you, because it feels similar to the state handling and in my opinion it is more readable.
答案2
得分: 0
"Easier" is subjective, so it's difficult to answer without also being subjective.
Immer (https://immerjs.github.io/immer/update-patterns/) allows writing updates that feel more "natural" to a lot of developers. Immer is also used under the hood for Redux Toolkit.
Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
, but Immer is typically more convenient.
Taking your example:
setArtists([
...artists,
{ id: nextId++, name: name }
]);
In Immer, it would look like:
setArtists(produce(draft => {
draft.push({id: nextId++, name });
}));
英文:
"Easier" is subjective, so it's difficult to answer without also being subjective.
Immer (https://immerjs.github.io/immer/update-patterns/) allows writing updates that feel more "natural" to a lot of developers. Immer is also used under the hood for Redux Toolkit.
> Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
, but Immer is typically more convenient.
Taking your example:
setArtists([
...artists,
{ id: nextId++, name: name }
]);
In Immer, it would look like:
setArtists(produce(draft => {
draft.push({id: nextId++, name });
}));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论