【问题标题】:Reactjs: How to select one or multiple cards when clicked with a state hook?Reactjs:使用状态挂钩单击时如何选择一张或多张卡片?
【发布时间】: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;

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

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

【问题讨论】:

    标签: javascript reactjs typescript react-hooks state


    【解决方案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 组件。在那里,您可以根据该道具应用您的样式。

    希望您的问题得到解答!

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 2020-08-15
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 2014-11-26
      相关资源
      最近更新 更多