javascript - 使用 setState() 更新数组时出现 React / TypeScript 错误
问题描述
我正在寻找使用从 setState 返回的更新程序来修改数组中一项的属性。该函数作为道具传递给孩子,然后孩子用自己的索引调用它来改变他们的状态。
const tryMarkHabitAsComplete = (index: number) => {
let list: HabitType[] = [...habitList];
let habit = {
...list[index],
isComplete: true,
};
list[index] = habit;
setHabitList({list});
};
使用
setHabitList(list);
数组运行时会被清除并变为未定义,因此在调用此函数一次后我无法使用它。
不断出现的错误是:
Argument of type '{ list: HabitType[]; }' is not assignable to parameter of type 'SetStateAction<HabitType[]>'. Object literal may only specify known properties, and 'list' does not exist in type 'SetStateAction<HabitType[]>'
我将状态视为不可变的,并尝试(我认为)设置状态。调试时,每次单击我都会清空我的习惯列表的数组。更进一步,我将状态定义为:
const [habitList, setHabitList] = useState<HabitType[]>([]);
如果我尝试以其他方式设置状态,则数组将变为未定义或空白并丢失信息。我应该澄清一下,这是一个使用 react-native 编写的副项目。
MRE编辑:
react-native 应用程序中的 2 个组件,丢弃 css 和不相关的导入: Chain.tsx
export type HabitType = {
text: string;
index: number;
isComplete: boolean;
tryMarkHabit: (index: number) => void;
};
const Chain = (props: any) => {
const [habitList, setHabitList] = useState<HabitType[]>([]);
// Set the initial state once w/ dummy values
useEffect(() => {
setHabitList([
{
text: "1",
index: 0,
isComplete: false,
tryMarkHabit: tryMarkHabitAsComplete,
},
{
text: "2",
index: 1,
isComplete: false,
tryMarkHabit: tryMarkHabitAsComplete,
}
]);
}, []);
// Only is previous item is complete, let habit be marked as complete
const tryMarkHabitAsComplete = (index: number) => {
let list: HabitType[] = [...habitList];
let habit = {
...list[index],
isComplete: true,
};
list[index] = habit;
setHabitList(list);
};
let habitKeyCount = 0;
return (
<View style={styles.container}>
{habitList.map((habit) => (
<Habit key={habitKeyCount++} {...habit} />
))}
</View>
);
};
export default Chain;
习惯.tsx
import { HabitType } from "./Chain";
const Habit = ({ text, index, isComplete, tryMarkHabit }: HabitType) => {
const [complete, setComplete] = useState<boolean>(false);
return (
<TouchableOpacity
style={complete ? styles.completeHabit : styles.uncompleteHabit}
onPress={() => tryMarkHabit(index)}
>
<Text style={styles.chainText}>{text}</Text>
</TouchableOpacity>
);
};
export default Habit;
当我按下一个习惯时,它会成功调用 tryMarkHabitAsComplete,但是它似乎清除了数组 - 据我所知,数组随后变得未定义。
解决方案
问题
如果我不得不猜测,我会说你habitList
在回调中有一个陈旧的外壳,它本身就是你状态的一个陈旧的外壳。
解决方案
我建议改为在您的处理程序中使用功能状态更新。功能更新允许从之前的状态更新您的状态,而不是更新排队的渲染周期中的状态。这是一个小而微妙但重要的区别。
我还建议不要将处理程序封闭在状态的外壳中。只需将其Habit
作为普通回调传递给,这样您就可以避免任何陈旧的外壳。
const Chain = (props: any) => {
const [habitList, setHabitList] = useState<HabitType[]>([]);
// Set the initial state once w/ dummy values
useEffect(() => {
setHabitList([
{
text: "1",
index: 0,
isComplete: false,
},
{
text: "2",
index: 1,
isComplete: false,
}
]);
}, []);
// Only is previous item is complete, let habit be marked as complete
const tryMarkHabitAsComplete = (index: number) => {
setHabitList(list => list.map((habit, i) => i === index ? {
...habit,
isComplete: true,
} : habit);
};
let habitKeyCount = 0;
return (
<View style={styles.container}>
{habitList.map((habit) => (
<Habit
key={habitKeyCount++}
{...habit}
tryMarkHabit={tryMarkHabitAsComplete}
/>
))}
</View>
);
};
编辑isComplete
样式
Habit
应该只使用传递的isComplete
道具来设置所需的 CSS 样式。
const Habit = ({ text, index, isComplete, tryMarkHabit }: HabitType) => {
return (
<TouchableOpacity
style={isComplete ? styles.completeHabit : styles.uncompleteHabit}
onPress={() => tryMarkHabit(index)}
>
<Text style={styles.chainText}>{text}</Text>
</TouchableOpacity>
);
};
推荐阅读
- java - 主要和 android.graphics.drawable.RippleDrawable
- reactjs - 组件从状态更改重新渲染,但对 DOM 没有影响
- ruby - 什么是`&&=`快捷方式?
- java - 如何制作一个与外部硬件通信的 asnychron REST 服务器
- c# - 尝试在 SQL Server 中更新 datagridview 上的值
- sql - 在 SQL Server 中,BCP shell 命令不是在一个服务器中写入文件,而是在另一个服务器中创建文件。这个问题需要任何许可吗?
- javascript - 浏览器调整大小再次运行功能,我该怎么做?
- python - 这段代码可以更简单吗?哪个代码看起来更好?[反向循环]
- r - 始终使用列表中的一行 n 个其他数据框创建所有可能的数据框
- python - 熊猫 to_datetime 方法