内部 .map() 样式 "this" Compenent (React.js)

inside .map() style "this" Compenent (React.js)

我已经映射了一组对象,如果单击其中一个元素,我想将该元素的颜色更改为红色(通过添加 CSS class),但它始终是彩色的所有的元素都是红色的。我以为 React 会自动获取上下文?我还需要使用 'this' 吗?

import React, { useState } from "react";

import './Map.css';

const Arr = [
  {
    id: "i1",
    item: "item-1",
  },
  {
    id: "i2",
    item: "item-2",
  },
  {
    id: "i3",
    item: "item-3",
  },
];

const ListElement = (props) => {
  return <li className={props.className} onClick={props.onClick}>{props.children}</li>;
};

const Map = () => {
  const [changedStyle, setChangedSTlye] = useState(false);
  const styleHandler = () => {
    changedStyle ? setChangedSTlye(false) : setChangedSTlye(true);
    console.log("clicked");
    console.log(changedStyle);
  };

  const List = Arr.map((l, index) => (
    <ListElement key={index} onClick={styleHandler} className={changedStyle ? 'map-selected' : ''}>
      {l.item}
    </ListElement>
  ));

  return List;
};

export default Map;
.map-selected{color:red;}

问题

这里的问题是changedStyle是一个状态变量。因此,它不是数组元素所独有的,而是影响所有元素,因为它是 react 组件的状态。您需要 changedStyle 作为元素中的 属性。

一个解决方案

您的元素中需要有一个 changedStyle 标志。您可以使用 onClick 单击时更改数组中的元素。您将根据标志 l.changedStyle 动态分配一个 class 名称。您希望您的数组是一个状态变量,以便 React 组件在更改后重新呈现。

import React, { useState } from "react";

import './Map.css';

const Arr = [
  {
    id: "i1",
    item: "item-1",
    changedStyle: false
  },
  {
    id: "i2",
    item: "item-2",
    changedStyle: false
  },
  {
    id: "i3",
    item: "item-3",
    changedStyle: false
  },
];

const ListElement = (props) => {
  return <li className={props.className} onClick={props.onClick}>{props.children}</li>;
};

const Map = () => {
  const [arr, setArr] = useState(Arr)
  const styleHandler = (index) => {
    const newArr = [...arr]
    const element = newArr[index]
    newArr.splice(index, 1, {...element, changedStyle: !element.changedStyle}
    setArr(arr)
  };

  const List = arr.map((l, index) => (
    <ListElement key={index} onClick={() => styleHandler(index)} className={l.changedStyle ? 'map-selected' : ''}>
      {l.item}
    </ListElement>
  ));

  return List;
};

export default Map;

一个推荐

如果您的数组元素中有唯一的 idkey,请不要在您的 jsx 中使用 key={index}。而是使用 key={l.id}

而不是有一个标志来改变颜色。您需要维护一个列表,该列表将在选中时将所选项目的索引推送到列表中,并在再次单击时将其弹出。

const Map = () => {
  const [ selectedItems , setSelectedItems] = useState([]);

  const styleHandler = (itemIndex) => {
    if(selectedItems.includes(itemIndex))
    {
      setSelectedItems(prevSelectedItems => prevSelectedItems.filter((item) => item !== itemIndex))
    } else {
      setSelectedItems(prevSelectedItems => [...prevSelectedItems, itemIndex])
    }
  };

  const List = Arr.map((l, index) => (
    <ListElement key={index} onClick={() => styleHandler(index)} className={selectedItems.includes(index) ? 'map-selected' : ''}>
      {l.item}
    </ListElement>
  ));

  return List;
};

我们正在将 index 传递给 styleHandler 。第一次单击该项目时,我们将在 state 中推送该项目的索引。如果为第二个项目单击了相同的项目,那么我们会将其从状态中删除。

const styleHandler = (itemIndex) => {
    if(selectedItems.includes(itemIndex))
    {
      setSelectedItems(prevSelectedItems => prevSelectedItems.filter((item) => item !== itemIndex))
    } else {
      setSelectedItems(prevSelectedItems => [...prevSelectedItems, itemIndex])
    }
  };

当 selectedItems 中存在项目索引时,我们应用样式

className={selectedItems.includes(index) ? 'map-selected' : ''}

这样就不需要维护添加标志或修改源数据了。