映射中的复选框在重构后数组更新时未更新以响应钩子



我使用钩子将类组件转换为函数组件。目前,我很难弄清楚为什么这个映射中的复选框没有用checked值更新,尽管onChange处理程序启动了,并在必要时更新了数组。(onSubmit也能正常工作,并正确地更新DB中的值(。

import {
Container,
Typography,
Grid,
Checkbox,
FormControlLabel,
Button
} from "@material-ui/core";
import Select from "react-select";
import localeSelect from "../services/localeSelect";
import {
linkCharactersToGame,
characterLinked,
linkCharacters
} from "../data/locales";
import dbLocale from "../services/dbLocale";
import { LanguageContext } from "../contexts/LanguageContext";
import { UserContext } from "../contexts/UserContext";
import { GameContext } from "../contexts/GameContext";
import { CharacterContext } from "../contexts/CharacterContext";
import { Redirect } from "react-router-dom";
export default function LinkCharacter() {
const { language } = useContext(LanguageContext);
const { user } = useContext(UserContext);
const { games, loading, error, success, connectCharacters } = useContext(
GameContext
);
const { characters } = useContext(CharacterContext);
const [game, setGame] = useState("");
const [selectedCharacters, setSelectedCharacters] = useState([]);
if (!user) {
return <Redirect to="/" />;
}
return (
<section className="link-character">
<Container maxWidth="sm">
<Typography variant="h5">
{localeSelect(language, linkCharactersToGame)}
</Typography>
{error && (
<p className="error">
<span>Error:</span> {error}
</p>
)}
{success && <p>{localeSelect(language, characterLinked)}</p>}
<Select
options={games.map(game => {
return {
label: dbLocale(language, game),
value: game._id
};
})}
onChange={e => {
setGame(e.value);
const selected = [];
const index = games.findIndex(x => x._id === e.value);
games[index].characters.forEach(character => {
selected.push(character._id);
});
setSelectedCharacters(selected);
}}
/>
</Container>
<Container maxWidth="md">
{game !== "" && (
<>
<Grid container spacing={2}>
{characters.map((character, index) => {
return (
<Grid item key={index} md={3} sm={4} xs={6}>
<FormControlLabel
control={
<Checkbox
value={character._id}
onChange={e => {
const index = selectedCharacters.indexOf(
e.target.value
);
if (index === -1) {
selectedCharacters.push(e.target.value);
} else {
selectedCharacters.splice(index, 1);
}
}}
color="primary"
checked={
selectedCharacters.indexOf(character._id) !== -1
}
/>
}
label={dbLocale(language, character)}
/>
</Grid>
);
})}
</Grid>
<Button
variant="contained"
color="primary"
onClick={e => {
e.preventDefault();
connectCharacters(game, selectedCharacters);
}}
>
{localeSelect(language, linkCharacters)}
</Button>
</>
)}
</Container>
</section>
);
}

我觉得Hooks中缺少了一些东西(或者Hooks处理这样的事情有某种问题(。我一直在四处寻找和询问,没有其他人也能解决这个问题。

[state, setState] = useState([])返回的state是您只应该从中读取的内容。如果修改它,React将不知道数据已经更改,需要重新渲染。当您需要修改数据时,您必须使用setState,或者在您的情况下使用setSelectedCharacters

此外,如果以后在其他地方读取数组,通过引用修改数据可能会导致不可预测的结果

除此之外,如果您给setState赋予与钩子在state中返回的值相同的值,React将完全跳过更新。当使用数字或字符串时,这不是问题,但当使用数组时,它就变成了问题,因为当内容可能发生变化时,引用(React用来判断是否存在差异的值(可能是相同的。因此,必须将一个新数组传递给setState

考虑到这一点,您的onChange函数可能看起来像:

onChange={e => {
const index = selectedCharacters.indexOf(
e.target.value
);
if (index === -1) {
// creating a new array with [], so the original one stays intact
setSelectedCharacters([...selectedCharacters, e.target.value]);
} else {
// Array.filter also creates new array
setSelectedCharacters(selectedCharacters.filter((char, i) => i !== index));
}
}}

医生来了https://en.reactjs.org/docs/hooks-reference.html#usestate

最新更新