在 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]);