在 React 的数组中设置对象的值?
Setting the values of an object in an array in React?
我正在用 React 构建一张可刷卡。该卡片包含 4 张幻灯片。卡片中显示的值取决于用户输入。
首先我定义了一个这样的示例对象:
const initialState = { id: '', title: '', name: '', image: ''};
在我的组件中,我将数组状态定义为:
const [card, setCard] = useState([initialState]);
我将卡片与用户输入字段并排显示,以便用户在撰写时查看卡片。因此,每当用户 adds/edits 卡的特定值时,他都可以在卡上实时查看它。
我们可以像这样为每个字段设置对象的状态:
<Input id='title' name='title' placeholder="Enter Title" type='text' value={card.title} onChange={handleChange}/>
处理更改函数:
const handleChange = (e) => {
setCard({ ...card, [e.target.name]: e.target.value });
}
但这对于上面提到的对象数组是不可能的。那么如何处理这种情况呢?
每当用户滑动 previous/next 卡片时,字段必须填充适当的值,以便他可以编辑它们。简单地说,用户必须能够随时编辑任何字段。每当用户添加新卡片时,必须将新对象推送到数组状态。
完整代码:
const initialState = { id: '', title: '', name: '', image: ''};
const Home = () => {
const [card, setCard] = useState([initialState]);
const isdisabled = true;
const handleChange = (e) => {
setCard({ ...card, [e.target.name]: e.target.value });
}
const handleAdd = () => {
//TODO
}
return (
<Flex>
<Center>
<Flex bg="white" w="lg" h="420" borderRadius="lg" m="7" p="2" alignItems="center">
<Box w="48" align="center">
<IconButton aria-label='Go to previous' disabled borderRadius="full" bg='gray.200' color='black' icon={<ChevronLeftIcon w={6} h={6}/>} />
</Box>
<Box>
<Image src={card[0].image} w="full" h="44" objectFit="cover" objectPosition="0 0" borderRadius="lg" />
<Heading color="black" size='lg'>{card[0].title}</Heading>
<Text color="black" size='40'>{card[0].namee}</Text>
</Box>
<Box w="48" align="center">
<IconButton aria-label='Go to previous' disabled borderRadius="full" bg='gray.200' color='black' icon={<ChevronRightIcon w={6} h={6}/>} />
</Box>
</Flex>
</Center>
<Flex direction="column" w="lg" gap="4" m="7">
<Input placeholder="Enter Title" value={card[0].title} onChange={handleChange}/>
<Input placeholder="Enter Name" value={card[0].name} onChange={handleChange}/>
<Button onClick={handleClick}>Upload Image</Button>
<Button onClick={handleAdd}>Add another slide</Button>
<Button colorScheme="blue">Done</Button>
</Flex>
</Flex>
)
}
export default Home
如何无缝地做到这一点?任何帮助,将不胜感激。谢谢。
你的卡片状态是对象数组需要更新数组第一个对象
const handleChange = (e) => {
const arr = [...card]
arr[0] = {...arr[0], [e.target.name]: e.target.value }
setCard(arr);
}
您可能需要一个额外的状态变量,指定活动卡
类似
const [cards, setCards] = useState([initialState]);
const [activeCardIndex, setActiveCardIndex] = useState(0);
handleGotoNext = useCallback(() => {
// you need to also handle not allowing to go beyond the max
setActiveCardIndex(prevActive => prevActive + 1);
}, []);
const handleGotoPrevious = useCallback(() => {
// you need to also handle not allowing to go below 0
setActiveCardIndex(prevActive => prevActive - 1);
}, []);
const handleChange = useCallback((e) => {
setCards(prevCards => prevCards.map((card, index) => {
if (index === activeCardIndex) {
return { ...card,
[e.target.name]: e.target.value
}
}
return card;
}));
}, [activeCardIndex]);
const handleAdd = useCallback(() => {
const newCards = [...cards, { ...initialState
}];
setCards(newCards);
setActiveCardIndex(newCards.length - 1);
}, [cards]);
const activeCard = cards[activeCardIndex];
// for the rendering you should use the activeCard constant, instead of cards[n]
return (
<Flex>
...
<Image src={activeCard.image} w="full" h="44" objectFit="cover" objectPosition="0 0" borderRadius="lg" />
...
</Flex>
)
@Gabriele Petrioli 的回答是解决我的问题的完美方法,只是需要稍微调整一下:
将 activeCardIndex
添加到两个导航处理程序的依赖列表:
const handleGotoNext = useCallback(() => {
// you need to also handle not allowing to go beyond the max
if(activeCardIndex < cards.length-1){
setActiveCardIndex(prevActive => prevActive + 1);
}
}, [activeCardIndex]);
const handleGotoPrevious = useCallback(() => {
// you need to also handle not allowing to go below 0
if(activeCardIndex > 0){
setActiveCardIndex(prevActive => prevActive - 1);
}
}, [activeCardIndex]);
和 handleChange
函数:
const handleChange = useCallback((e) => {
setCards(prevCards => prevCards.map((card, index) => {
if (index === activeCardIndex) {
return { ...card,
[e.target.name]: e.target.value
}
}else {
return card;
}
}));
}, [activeCardIndex]);
我正在用 React 构建一张可刷卡。该卡片包含 4 张幻灯片。卡片中显示的值取决于用户输入。
首先我定义了一个这样的示例对象:
const initialState = { id: '', title: '', name: '', image: ''};
在我的组件中,我将数组状态定义为:
const [card, setCard] = useState([initialState]);
我将卡片与用户输入字段并排显示,以便用户在撰写时查看卡片。因此,每当用户 adds/edits 卡的特定值时,他都可以在卡上实时查看它。
我们可以像这样为每个字段设置对象的状态:
<Input id='title' name='title' placeholder="Enter Title" type='text' value={card.title} onChange={handleChange}/>
处理更改函数:
const handleChange = (e) => {
setCard({ ...card, [e.target.name]: e.target.value });
}
但这对于上面提到的对象数组是不可能的。那么如何处理这种情况呢? 每当用户滑动 previous/next 卡片时,字段必须填充适当的值,以便他可以编辑它们。简单地说,用户必须能够随时编辑任何字段。每当用户添加新卡片时,必须将新对象推送到数组状态。
完整代码:
const initialState = { id: '', title: '', name: '', image: ''};
const Home = () => {
const [card, setCard] = useState([initialState]);
const isdisabled = true;
const handleChange = (e) => {
setCard({ ...card, [e.target.name]: e.target.value });
}
const handleAdd = () => {
//TODO
}
return (
<Flex>
<Center>
<Flex bg="white" w="lg" h="420" borderRadius="lg" m="7" p="2" alignItems="center">
<Box w="48" align="center">
<IconButton aria-label='Go to previous' disabled borderRadius="full" bg='gray.200' color='black' icon={<ChevronLeftIcon w={6} h={6}/>} />
</Box>
<Box>
<Image src={card[0].image} w="full" h="44" objectFit="cover" objectPosition="0 0" borderRadius="lg" />
<Heading color="black" size='lg'>{card[0].title}</Heading>
<Text color="black" size='40'>{card[0].namee}</Text>
</Box>
<Box w="48" align="center">
<IconButton aria-label='Go to previous' disabled borderRadius="full" bg='gray.200' color='black' icon={<ChevronRightIcon w={6} h={6}/>} />
</Box>
</Flex>
</Center>
<Flex direction="column" w="lg" gap="4" m="7">
<Input placeholder="Enter Title" value={card[0].title} onChange={handleChange}/>
<Input placeholder="Enter Name" value={card[0].name} onChange={handleChange}/>
<Button onClick={handleClick}>Upload Image</Button>
<Button onClick={handleAdd}>Add another slide</Button>
<Button colorScheme="blue">Done</Button>
</Flex>
</Flex>
)
}
export default Home
如何无缝地做到这一点?任何帮助,将不胜感激。谢谢。
你的卡片状态是对象数组需要更新数组第一个对象
const handleChange = (e) => {
const arr = [...card]
arr[0] = {...arr[0], [e.target.name]: e.target.value }
setCard(arr);
}
您可能需要一个额外的状态变量,指定活动卡
类似
const [cards, setCards] = useState([initialState]);
const [activeCardIndex, setActiveCardIndex] = useState(0);
handleGotoNext = useCallback(() => {
// you need to also handle not allowing to go beyond the max
setActiveCardIndex(prevActive => prevActive + 1);
}, []);
const handleGotoPrevious = useCallback(() => {
// you need to also handle not allowing to go below 0
setActiveCardIndex(prevActive => prevActive - 1);
}, []);
const handleChange = useCallback((e) => {
setCards(prevCards => prevCards.map((card, index) => {
if (index === activeCardIndex) {
return { ...card,
[e.target.name]: e.target.value
}
}
return card;
}));
}, [activeCardIndex]);
const handleAdd = useCallback(() => {
const newCards = [...cards, { ...initialState
}];
setCards(newCards);
setActiveCardIndex(newCards.length - 1);
}, [cards]);
const activeCard = cards[activeCardIndex];
// for the rendering you should use the activeCard constant, instead of cards[n]
return (
<Flex>
...
<Image src={activeCard.image} w="full" h="44" objectFit="cover" objectPosition="0 0" borderRadius="lg" />
...
</Flex>
)
@Gabriele Petrioli 的回答是解决我的问题的完美方法,只是需要稍微调整一下:
将 activeCardIndex
添加到两个导航处理程序的依赖列表:
const handleGotoNext = useCallback(() => {
// you need to also handle not allowing to go beyond the max
if(activeCardIndex < cards.length-1){
setActiveCardIndex(prevActive => prevActive + 1);
}
}, [activeCardIndex]);
const handleGotoPrevious = useCallback(() => {
// you need to also handle not allowing to go below 0
if(activeCardIndex > 0){
setActiveCardIndex(prevActive => prevActive - 1);
}
}, [activeCardIndex]);
和 handleChange
函数:
const handleChange = useCallback((e) => {
setCards(prevCards => prevCards.map((card, index) => {
if (index === activeCardIndex) {
return { ...card,
[e.target.name]: e.target.value
}
}else {
return card;
}
}));
}, [activeCardIndex]);