Reactjs:使用状态挂钩单击时如何选择一张或多张卡片?

Posted

技术标签:

【中文标题】Reactjs:使用状态挂钩单击时如何选择一张或多张卡片?【英文标题】:Reactjs: How to select one or multiple cards when clicked with a state hook? 【发布时间】:2021-09-22 03:00:00 【问题描述】:

我有一个卡片组件 TemplateList 用于映射我的模板卡片(我通过数组添加它们)。

我想添加一个 onClick 状态挂钩功能,帮助我在点击时选择一张或多张卡片,我该怎么做?

这是我的 TemplateList 组件:

import TemplateCard from 
import styles from "./styles/actionpage.m.css";

export type Template = 
    title: string;
    description: string;
    imgURL: string;
;

type Props = 
    templates: Template[];
;

const TemplateList = ( templates : Props) => 
    return (
        <div className=styles.scrollContainer>
            templates.map((item) => (
                <TemplateCard
                    title=item.title
                    description=item.description
                    img=item.imgURL
                    classNameToAdd=styles.cardContainer
                />
            ))
        </div>
    );
;

export default TemplateList;

这是我的 TemplateCard 组件:

import React from "react";
import styles from "./styles/cards.m.css";

type Props = 
    title: string;
    description: string;
    img: string;
    classNameToAdd?: string;
    selected?: boolean;
    classNameOnSelected?: string;
;

const TemplateCard = (
    title,
    description,
    img,
    classNameToAdd,
    classNameOnSelected,
    selected,
: Props) => 
    const  aspectRatio, vmin  = useWindowResponsiveValues();
    let className = `$styles.card $classNameToAdd`;

    if (selected) 
        className += `$styles.card $classNameToAdd $classNameOnSelected`;
    

    return (
        <div style=card className=className>
            <img style=imageSize src=img></img>
            <div style=cardTitle>title</div>
            <div style=descriptionCard>description</div>
        </div>
    );
;

TemplateCard.defaultProps = 
    classNameOnSelected: styles.selected,
;

export default TemplateCard;

目前,我添加了一个“已选择”道具,在为真时为我的卡片提供边框,但这当然会在为真时选择所有卡片。

这就是我的卡片在被选中时的样子。

【问题讨论】:

【参考方案1】:

要解决这个问题,您必须为每张卡设置自己的状态; selected。 这样每张卡片都会有自己的小逻辑,通过这些逻辑他们可以知道自己是否被选中。

// TemplateCard.js
...

const TemplateCard = (
    title,
    description,
    img,
    classNameToAdd,
    classNameOnSelected,
    /* selected,  we will make this a state instead of prop */
: Props) => 
    const  aspectRatio, vmin  = useWindowResponsiveValues();

    const [selected, setSelected] = useState(false); // Added state

    // Added handler
    const handleClick = () => 
      setSelected(!selected);
    ;

    if (selected) 
        className += `$styles.card $classNameToAdd $classNameOnSelected`;
    

    return (
        <div style=card className=className onClick=handleClick>
            <img style=imageSize src=img></img>
            <div style=cardTitle>title</div>
            <div style=descriptionCard>description</div>
        </div>
    );
;
...

【讨论】:

太棒了!我刚刚添加了它,现在它应该选择我的卡片。不过,我会有一个问题,我在控制台中收到此警告,但不知道为什么会这样: 列表中的每个孩子都应该有一个唯一的“key”道具。检查TemplateList的渲染方法。有关更多信息,请参阅 react-warning-keys。在 TemplateCard(由 TemplateList 创建)在 TemplateList(由 ActionPageNew 创建) 每当你通过 map 方法渲染一个 React 组件列表时,你还必须为每个 React 组件提供一个 key prop。您可以在 react docs 上找到更多信息。【参考方案2】:

在您的 TemplateCard 组件上添加一个 onClick 处理程序并在主 div 上触发它。此外,您需要为您的个人卡提供一些标识,以便我们可以使用其来源的数组索引。

像这样:

const TemplateCard = (
    title,
    description,
    img,
    classNameToAdd,
    classNameOnSelected,
    selected,
    handleClick
    index
: Props) => 
    const  aspectRatio, vmin  = useWindowResponsiveValues();
    let className = `$styles.card $classNameToAdd`;

    if (selected) 
        className += `$styles.card $classNameToAdd $classNameOnSelected`;
    

    return (
        <div style=card className=className onClick=()=>handleClick(index)>
            <img style=imageSize src=img></img>
            <div style=cardTitle>title</div>
            <div style=descriptionCard>description</div>
        </div>
    );
;

在您的 TemplateList 组件中,您需要设置一个索引数组(使用 useState)来存储单击的 TemplateCards 的索引,以便您可以检查选择了哪些卡,哪些没有。并使用我们传递给子组件的函数设置状态,即handleClick

像这样:

const [selectedArray,setSelectedArray]=useState([])

const handleClick=(i)=>
const tempArray =[...selectedArray]
if(tempArray[i]==i)tempArray[i]=undefined
else tempArray[i]=i

setSelectedArray(tempArray)

组件将是这样的:

const TemplateList = ( templates : Props) => 
    return (
        <div className=styles.scrollContainer>
            templates.map((item,index) => (
                <TemplateCard
                    title=item.title
                    description=item.description
                    img=item.imgURL
                    classNameToAdd=styles.cardContainer
                    index=index
                    selected=selectedArray[index]==index? true:false
                    handleClick=handleClick
                />
            ))
        </div>
    );
;

现在这里发生的情况是,我们使用索引作为标识符,并基于此设置选定卡片的数组。在此基础上,我们将 'selected' 属性发送到 Card 组件。在那里,您可以根据该道具应用您的样式。

希望您的问题得到解答!

【讨论】:

以上是关于Reactjs:使用状态挂钩单击时如何选择一张或多张卡片?的主要内容,如果未能解决你的问题,请参考以下文章

如果ID存在于第二张或第三张表中,如何从第一张表中高效选择?

如何在reactjs中更新地图功能中的状态

如何防止在单击事件上触发两个相同的 useState 挂钩

如何通过单击按钮从反应状态挂钩数组中删除对象

如何在reactjs挂钩中创建自定义挂钩?

ReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据