React中如何使用map创建独立的子元素

How to use map in React to create independent children elements

我可以成功地使用 map 从我的数组内部创建多个元素,但是我正在创建的按钮和我分配给每个子元素的状态似乎与第一个映射有关。在此处编写代码以及屏幕截图。

import React, {useState} from 'react';
import './Switch.css'

const Switch = () => {
    const [status, setStatus] = useState(true);  
    
    const meats = [
        "Chicken", 
        "Ground Beef",
        "Sausage"
    ]

    const meatSwitches = meats.map((meat) =>
    
            <>
            <div id="ingredientContainer" className={status === true ? 'containerYes' : 'containerNo'}>
                
                    <h2 id='ingredientLabel'>{meat}</h2>
                    <div id="underLabel">
                        <h3 id='yes'>Sounds Yummy! </h3>
                        <input
                            className="react-switch-checkbox"
                            id={`react-switch-new`}
                            type="checkbox"
                            onClick={() => setStatus(!status)}
                            
                        />
                        <label
                            className="react-switch-label"
                            htmlFor={`react-switch-new`}
                        >
                            <span className={`react-switch-button`} />
                        </label>
                        <h3 id='no'>No, thanks.</h3>
                    </div>
                </div>
            </>
    );

如何让每个子元素都有一个功能按钮,第一个按钮和独立状态(在本例中 'true' 和 'false')。

有两种常见的方法:

1.使用自己的单个 boolean 状态 创建一个 Meat 子组件 并将此状态保持在子级别,独立于父组件 Switch。如果需要,您可以通过回调函数 onStatusChangestatus 数据传回父级,例如使用 useEffect().

  const Meat = ({ meat, onStatusChange } ) => {
    const [status, setStatus] = useState(true);
    
    useEffect(() => onStatusChange(status), [status])
    
    return (
    <div
      id="ingredientContainer"
      className={status === true ? 'containerYes' : 'containerNo'}
    >
      // ... your jsx code here
    </div>
  }

您的 Switch 组件将如下所示:

const Switch = () => {
    const meats = [
        "Chicken", 
        "Ground Beef",
        "Sausage"
    ]

    const [statusList, setStatusList] = useState([]);  
    const handleStatusChange = (status) => {
      // do what you want with the individual status,
      // perhaps push it in a status array?
      setStatusList((prev) => [...prev, status]);
    };

    const meatSwitches = meats.map((meat) => 
      <Meat key={meat} meat={meat} onStatusChange={handleStatusChange} />
    )

2。使用肉类型数组而不是布尔状态来存储复选框值,然后在需要时将其转换为布尔值。使用这种方法,您不必创建新的 Meat 子组件。

const Switch = () => {
    const [status, setStatus] = useState([]);  
    
    const meats = [
        "Chicken", 
        "Ground Beef",
        "Sausage"
    ];
    
    const handleStatusChange = (event, meat) => {
      if (event.target.checked) {
        // push meat type to list
        // when box is checked
        setStatus(prev => [...prev, meat]);
      } else {
        // remove meat type from list
        // when box is unchecked
        setStatus(prev => return prev.filter(type => type !== meat));
      }
    };

    const meatSwitches = meats.map((meat) =>
      <div
        {/* id and key need to be unique */}
        id={`ingredientContainer-${meat}`}
        key={meat}
        {/* check if box is checked */}
        className={status.includes(meat) ? 'containerYes' : 'containerNo'}
      >
        // code
        <input
          type="checkbox"
          onClick={(event) => handleStatusChange(event, meat)}
        />
        // ...
      </div>
    )

如果这回答了您的问题,请告诉我。

您可以将状态设置为布尔数组,并让每个按钮对应于索引。示例:

const status, setStatus = useState([true, true, true])
const handleChange = (index) => {
  const prev = [...status];
  prev[index] = !prev[index];
  setStatus(prev);
  
}
const meatSwitches = meats.map((meat,index) =>

        <>
        <div id="ingredientContainer" className={status === true ? 'containerYes' : 'containerNo'}>
            
                <h2 id='ingredientLabel'>{meat}</h2>
                <div id="underLabel">
                    <h3 id='yes'>Sounds Yummy! </h3>
                    <input
                        className="react-switch-checkbox"
                        id={`react-switch-new`}
                        type="checkbox"
                        onClick={() => handleChange(index)}
                        
                    />
                    <label
                        className="react-switch-label"
                        htmlFor={`react-switch-new`}
                    >
                        <span className={`react-switch-button`} />
                    </label>
                    <h3 id='no'>No, thanks.</h3>
                </div>
            </div>
        </>
);

代码在下方略有扩展 'answered'。感谢@kvooak 的帮助。事实证明,隐藏在 CSS 中的复选框有利于无响应按钮(实际上只是一些 CSS 而没有 'input' 功能)是我需要的。我使该复选框可见,添加到一个函数中以根据选中状态向数组添加或从数组中删除项目,并在最后实时打印该数组以证明该应用程序是 holding/dumping 数组中的正确项目所有成分。

import React, {useState} from 'react';
import './Switch.css'


const Switch = () => {
    const [status, setStatus] = useState([]); 
    const [checked, setChecked] = useState([]); 
    
    let meats = [
        "Chicken", 
        "Ground Beef",
        "Sausage",
        "Pork Chops"
    ];

    let starches = [
        "White Rice", "Bread", "Pasta",
        "Chips", "Idaho Potatoes", "Sweet Potatoes",
        "Tortillas", "Brown Rice", "Red Potatoes"
    ];

    const vegatables = [
        "Broccoli", "Green Beans", "Squash",
        "Corn", "Okra", "Carrots",
        "Onions", "Okra", "Zucchini"
    ]

    const spices = [
        "Cayenne Pepper", "Cumin", "Garlic Powder", 
        "Onion Powder", "Tumeric", "Garam Masala",
        "Chili Powder", "Crushed Red Pepper", "Oregano"
    ]

    let allIngredients = [...checked];

    const handleStatusChange = (event, ingredient) => {
        if (event.target.checked) {
          setStatus(prev => [...prev, ingredient]);
          allIngredients = [...checked, event.target.value];
        } else {
          setStatus(prev => prev.filter(type => type !== ingredient));
          allIngredients.splice(checked.indexOf(event.target.value), 1);
        }
        setChecked(allIngredients);
      };

      var checkedItems = checked.length
        ? checked.reduce((total, item) => {
            return total + ", " + item;
        })
        : "";

    const meatSwitches = meats.map((meat) =>
    
            <>
            <div id="ingredientContainer"  className={status.includes(meat) ? 'containerYes' : 'containerNo'}>
                
                    <p key={meat} id='ingredientLabel'>{meat}</p>
                    
                    <div id="underLabel">
                        <input
                            className="react-switch-checkbox"
                            value = {meat}
                            id={`react-switch-new`}
                            type="checkbox"
                            onClick={(event) => handleStatusChange(event, meat)}
                            
                        />
                        
                    </div>
                </div>
            </>
    );

    const starchSwitches = starches.map((starch) =>
    
    <>
    <div id="ingredientContainer"  className={status.includes(starch) ? 'containerYes' : 'containerNo'}>
        
            <p key={starch} id='ingredientLabel'>{starch}</p>
            
            <div id="underLabel">
                <input
                    className="react-switch-checkbox"
                    value={starch}
                    id={`react-switch-new`}
                    type="checkbox"
                    onClick={(event) => handleStatusChange(event, starch)}
                    
                />
                
            </div>
        </div>
    </>
);

const vegatableSwitches = vegatables.map((vegatable) =>
    
<>
<div id="ingredientContainer"  className={status.includes(vegatable) ? 'containerYes' : 'containerNo'}>
    
        <p key={vegatable} id='ingredientLabel'>{vegatable}</p>
        
        <div id="underLabel">
            <input
                className="react-switch-checkbox"
                value={vegatable}
                id={`react-switch-new`}
                type="checkbox"
                onClick={(event) => handleStatusChange(event, vegatable)}
                
            />
            
        </div>
    </div>
</>
);

const spiceSwitches = spices.map((spice) =>
    
<>
<div id="ingredientContainer"  className={status.includes(spice) ? 'containerYes' : 'containerNo'}>
    
        <p key={spice} id='ingredientLabel'>{spice}</p>
        
        <div id="underLabel">
            <input
                className="react-switch-checkbox"
                value={spice}
                id={`react-switch-new`}
                type="checkbox"
                onClick={(event) => handleStatusChange(event, spice)}
                
            />
            
        </div>
    </div>
</>
);

    return (
    <>
        {meatSwitches}
        {starchSwitches}
        {vegatableSwitches}
        {spiceSwitches}
        {checkedItems}
    </>
  );
};

export default Switch;