我正在尝试增加Attribute的一个对象属性的值(STR,AGI,INT,和CHA)每当“加”按钮,每一个都被点击。我已经弄清楚了如何使每个按钮和属性显示在我的网站上,但我试图找到一种更直观的方法来使用useReducer操作增加每个属性的值。我以前的解决方案是为每个属性创建一个单独的useReducer操作,该操作将使该操作所绑定的属性递增一。这导致了大量多余的代码,我正在尝试找到一个更好的解决方案。我想创建一个单一的“inc_Attributes”一个允许每个属性的值单独增加的动作,而不需要一个单独的动作来增加每个Attribute属性。我怎样做一个useReducer动作来做到这一点?
在index.tsx中,它表示“({[key]:value + 1}))”是未知类型,并显示为错误,尽管我在attributes.tsx中使用value几乎相同的方式,它工作得非常好。另一件值得注意的事情是,每当我按下其中一个与Attribute属性绑定的按钮时,它会给我错误:“错误:对象作为React子级无效(找到:对象的属性名{/Attributes object property name here/})。如果你想呈现一个子对象的集合,请使用数组。
index.tsx:
import { createContext, Dispatch, useReducer } from 'react'
import Background from '@/components/background';
import Attributes from '@/components/attributes';
import Proficiencies from '@/components/proficiencies';
import Skills from '@/components/skills';
export const context = createContext<{ contextState: any, contextDispatch: Dispatch<string> } | null>(null);
export const initialState = {
Level: 1,
Background: {
Gender: "",
Father: "",
Early_Life: "",
Adulthood: "",
Adventuring_Reason: "",
},
Attribute_Points: 4,
Attributes: {
STR: 5,
AGI: 5,
INT: 4,
CHA: 5
},
Skill_Points: 0,
Skills: {
Ironflesh: 1,
Power_Strike: 1,
Power_Throw: 1,
Power_Draw: 1,
Weapon_Master: 1,
Shield: 1,
Athletics: 1,
Riding: 2,
Horse_Archery: 1,
Looting: 1,
Trainer: 1,
Tracking: 1,
Tactics: 1,
Path_Finding: 1,
Spotting: 1,
Inventory_Management: 1,
Wound_Treatment: 1,
Surgery: 1,
First_Aid: 1,
Engineer: 1,
Persuasion: 1,
Prisoner_Management: 1,
Leadership: 2,
Trade: 1
},
Proficiency_Points: 0,
Proficiencies: {
One_Handed_Weapons: 23,
Two_Handed_Weapons: 15,
Polearms: 20,
Archery: 15,
Crossbows: 15,
Throwing: 19
}
}
export default function Home() {
const reducer = (state: any, action: string) => {
switch(action) {
case "inc_Attributes":
return {
...state,
Attributes: Object.entries(state.Attributes).map(([key, value]) => ({[key]: value + 1}))
}
}
}
const [state, dispatch] = useReducer(reducer, initialState)
return (
<context.Provider value={{contextState: state, contextDispatch: dispatch}}>
<Attributes />
</context.Provider>
)
}
attributes.tsx:
import { useContext } from 'react';
import { context } from '../pages/index';
export default function Attributes() {
const stateContext = useContext(context);
return (
<div>
{Object.entries(stateContext?.contextState.Attributes).map(([key, value]) => (
<ul>
<button onClick={() => stateContext?.contextDispatch('inc_Attributes')}>+</button>
<p>{key} {value}</p>
</ul>
))}
</div>
)
}
我试着查看React给我的错误,但没有一个解决方案对我有帮助。我还试着用“[keys:string]:number”,但我找不到一种方法将它插入到我的操作中,而不会给予我一个错误消息。
1条答案
按热度按时间qvtsj1bj1#
由于
contextState
看起来有一个固定的结构,我认为为它的许多(如果不是全部的话)属性明确地定义类型是有帮助的,这可能会防止像reducer
中当前错误那样的潜在错误。在上演示以下基本示例:stackblitz
定义
contextState
的类型,指定Attributes
(可能还有更多)属性。在这里,action
是用字符串type
和对象payload
构造的,字符串type
用于标记reducer
中的操作类型,对象payload
用于携带值,例如在这里增加的目标属性,但这是可选方法。在
reducer
中,考虑使用reduce()
而不是map()
来迭代Attributes
的[key, value]
,以便将结果保存为state
中要更新的对象。在这里,我认为添加
!
以省略对Attributes
的undefined
检查是安全的(因为它总是被给定初始值),但是如果不希望这样,可以在运行时检查undefined
的值。在使用
contextDispatch
的地方,传递字符串type
和前面定义的结构中的对象payload
,以便可以通过此操作更新一个或多个属性。虽然action类型仍然是
"inc_Attributes"
,但考虑到它在reducer
中的连接方式,我认为用减号减小值也应该可以。