reactjs 更新.map React中当前元素的状态

r6hnlfcb  于 2022-11-22  发布在  React
关注(0)|答案(1)|浏览(164)

我有一个.map函数可以创建一系列下拉菜单。我使用一个名为setDropdown的状态来打开和关闭下拉菜单。我注意到,当你打开.map中的任何一个下拉菜单时,它都会打开所有下拉菜单。我想知道你如何使用.map函数的index来更改当前下拉菜单的状态,而不是所有下拉菜单。
这是组件
下拉菜单位于{/* Quantity dropdown */}

import React, { useState, useEffect } from 'react'
import axios from 'axios';

export default function CheckoutPage() {
    const [rows, setRows] = useState([]);
    
    const quantityOptions = [
        { value: 1, label: '1' },
        { value: 2, label: '2' },
        { value: 3, label: '3' },
        { value: 4, label: '4' },
        { value: 5, label: '5' },
        { value: 6, label: '6' },
        { value: 7, label: '7' },
        { value: 8, label: '8' },
        { value: 9, label: '9' },
        { value: 10, label: '10' },
    ];

    const [dropdown, setDropdown] = useState(false)

    useEffect(() => {
        axios.get('http://localhost:8080/checkout/get')
            .then(res => {
                setRows(res.data);
            })
            .catch(err => {
                console.log(err);
            });
    }, []);

    return (
        <div class="w-screen bg-gray-50">
            {/* Product card */}
            {rows.map((row, index) => {
                return (
                    <div key={index}>
                        <div class="flex flex-col sm:flex-row justify-between space-y-5 sm:space-y-0">
                            {/* Product information */}
                            <div class="flex flex-col sm:flex-row sm:space-x-5">
                                <div class="order-2 sm:order-1 mt-5 sm:mt-0 overflow-hidden bg-gradient-to-t from-gray-200 to-white">
                                    <img src={row.image} alt="Product thumbnail" class="object-fit sm:w-full mx-auto h-60 sm:h-36 hover:scale-105 transition duration-300 ease-in-out"></img>
                                </div>

                                <div class="order-1 sm:order-2 flex flex-col justify-between">
                                    <div>
                                        <div class="font-medium">{row.product_name}</div>
                                        <div class="mt-2.5 text-sm text-gray-500">Product type</div>
                                    </div>

                                    <div>£ {row.price}</div>
                                </div>
                            </div>

                            <div class="flex flex-row sm:flex-col items-center sm:items-end justify-between">
                                {/* Delete button */}
                                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="order-2 sm:order-1 w-6 h-6 text-violet-600"> {/* Attribute: https://heroicons.com/ */}
                                    <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
                                </svg>

                                {/* Quantity dropdown */}
                                <div class="order-1 sm:order-2 relative sm:w-full cursor-pointer"> 
                                    <div 
                                        onClick={() => setDropdown(!dropdown)}
                                        class="flex justify-between items-center py-2 px-4 space-x-5 border rounded"
                                    >
                                        <label class="text-gray-500 cursor-pointer">{row.quantity}</label>

                                        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> {/* Attribution to https://heroicons.com/ */}
                                            <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
                                        </svg>
                                    </div>

                                    <ul 
                                        class={`${
                                            dropdown ? 'block' : 'hidden'
                                        } absolute w-full z-10 mt-2 py-2.5 px-4 space-y-2.5 border rounded bg-white`}
                                    >
                                        {quantityOptions.map((option, index) => {
                                            return (
                                                <li 
                                                    key={index} 
                                                    onClick={() => {setDropdown(false)}}
                                                    class="cursor-pointer text-gray-500"
                                                >
                                                    {option.label}
                                                </li>
                                            )
                                        })}
                                    </ul>
                                </div>
                            </div>

                        </div>

                        <hr class="my-5 -mx-5"></hr>
                    </div>
                )    
            })}
        </div>
    );
};
mzmfm0qo

mzmfm0qo1#

为了跟踪每个下拉菜单,我们需要一个对象状态,在这种情况下,你可以使用数组,但我更喜欢对象,因为它更安全。
我们创建了一个handleDropdownToggle,它接受一个键,我们可以使用这个键来确定我们要切换哪个下拉列表。注意,这个键必须是唯一的。

const [dropdown, setDropdown] = useState({});

const handleDropdownToggle = (key) => {
  setDropdown((prev) => {
    // if the key is not yet in the object set it to a default false
    if (!(key in prev)) prev[key] = false;
    return {
      ...prev,
      [key]: !prev[key],
    };
  });
};

在返回组件时,我们添加了handleDropdownToggle,并给予它row.product_name(假设这是唯一的)。现在单击切换图标将隐藏/显示下拉列表。

{/* Quantity dropdown */}
<div class="order-1 sm:order-2 relative sm:w-full cursor-pointer">
  <div
    onClick={() => handleDropdownToggle(row.product_name)}
    class="flex justify-between items-center py-2 px-4 space-x-5 border rounded"
  >

当决定显示/隐藏下拉菜单时,可以使用key从状态中获取值

<ul
  class={`${
    dropdown[row.product_name] ? "block" : "hidden"
  } absolute w-full z-10 mt-2 py-2.5 px-4 space-y-2.5 border rounded bg-white`}
>

当点击下拉菜单中的一个项目时,如果我们想将下拉菜单设置为false,我们只需将给定key上的状态更新为false

<li
  key={index}
  onClick={() => {
    setDropdown((prev) => {
      return {
        ...prev,
        [row.product_name]: false,
      };
    });
  }}
  class="cursor-pointer text-gray-500"
>
  {option.label}
</li>

相关问题