【问题标题】:useState updating for all list elements所有列表元素的 useState 更新
【发布时间】:2023-03-13 22:25:01
【问题描述】:

Before Clicking on picture

After clicking on picture

所以我使用 useState 来处理边距,并使描述滑下 div,该 div 最初隐藏在图像本身的后面。我正在使用 map() 来显示具有相同属性的图像列表。但是使用单个图像时 useState 可以正常工作。对于多个图像,单击 o 1 个图像会激活所有图像的向下滑动 div。我希望他们分开。有什么解决办法吗?

import React,{useState}  from 'react'
import Image1 from '../../images/background1.jpg'
import Image2 from '../../images/background2.jpg'
import {Arts,ArtHeading,CardContainer, Card,CardImg1,CardDetails,CardText} from './ArtsElements';

const images = [
    { title:"Title1", src:Image1},
    { title:"Title2", src:Image1},
    { title:"Title3", src:Image1},
    { title:"Title4", src:Image1},
    { title:"Title5", src:Image1},
    { title:"Title6", src:Image1},
    { title:"Title7", src:Image1},
    { title:"Title8", src:Image1},
    { title:"Title9", src:Image1},
    { title:"Title10", src:Image1},
    { title:"Title11", src:Image1},
    { title:"Title12", src:Image1},
    { title:"Title13", src:Image1},
    { title:"Title14", src:Image1},
];

const Artworks = () => {
    const [isOpen,setIsOpen] = useState(true);
    const toggle = () => {
        setIsOpen(!isOpen)
    }
    return (
        <Arts >
            <ArtHeading>
                Artworks
            </ArtHeading>
        <CardContainer>
        {
        images.map((img,index) => (
            
                
                    
                <Card >
                    
                    {/* <CardImg1 key={index} src={img.src}   /> */}
                    <CardImg1  src={Image1}  onClick={toggle} />
                    <CardDetails isOpen={isOpen} onClick={toggle} >
                                <CardText >
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 
                                 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                 title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4title 4
                                </CardText>
                    </CardDetails>
                    
                    
                </Card>
           
              
            
        ))} 
            
            </CardContainer>
            </Arts>
    )
}

export default Artworks

样式化组件文件:

import styled from 'styled-components'


export const Arts = styled.div`
background-color: #fff;
margin-bottom: 150px;
@media screen and  (max-width:768px){
    margin-bottom: 100px;
}
@media screen and  (max-width:480px){
    margin-bottom: 100px;
}
`
export const ArtHeading = styled.h1`
font-size: 50px;
margin-left: 0px;
font-weight: bold;
font-family: Verdana, Geneva, Tahoma, sans-serif;
text-align: center;
@media screen and  (max-width:768px){
    font-size: 50px;
    margin-left: 10px;
}
@media screen and  (max-width:480px){
    font-size: 30px;
    margin-left: 0px;
}

`

export const CardContainer = styled.section`
margin: 50px auto;
width: 90%;
display: grid;
grid-template-columns: repeat(3,1fr);
grid-gap: 20px;




`

export const Card = styled.div`


position: relative;
height: 430px;
width:350px;
border-radius: 10px;
box-shadow: 0px 5px 10px rgb(0,0,0,0.5); 

`



export const CardImg1 = styled.img`

width: 100%;
height:100%;
box-sizing: border-box;
border-radius: 10px;

`

export const CardText = styled.p`

`

export const CardDetails = styled.div`
background: white;
border-radius: 10px;
margin-top:${({isOpen}) => (isOpen ? '40px' : '440px')};
transition: 1s ease-in-out;
cursor: pointer;
`

【问题讨论】:

    标签: reactjs use-state


    【解决方案1】:

    打开所有的原因是你只为切换设置真或假。但你并没有告诉反应要切换哪个。所以你可以使用索引作为键来比较哪个被点击。 第一次改变

    <CardImg1  src={Image1}  onClick={()=>toggle(index)} />
    <CardDetails isOpen={(isOpen==index)?true:false} onClick={()=>toggle(index)} >
    

    然后方法

    const toggle = (index) => {
        
            setIsOpen(index)
            
    }
    

    然后使用状态

      const [isOpen,setIsOpen] = useState(null);
    

    更新:

    const toggle = (index) => {
            (isOpen==index)? setIsOpen(-1): setIsOpen(index);
            return false;
            }
    

    【讨论】:

    • 什么是currentCard?错误:'currentCard' 未定义 no-undef
    • 更新了我的答案,应该是 isOpen。我后来尝试使用其他逻辑,然后使用了与您使用的相同的逻辑
    • 错误:重新渲染太多。 React 限制了渲染的数量以防止无限循环。 ▶ 26 个堆栈帧被折叠。弹出这个错误
    • 是的,它工作正常,但单击图片会使向下滑动返回。单击另一张图片可以做到这一点。有没有什么方法可以让点击同一张图片的时候也往下滑?
    • 你的意思是说。如果它被点击了,你需要关闭卡片的详细信息,即使它打开是正确的
    【解决方案2】:
    /*
     * You have to distinguish one image from thes rest
     * Currently, you are using one `open` state for all of the images
     *
     */
    
    const [images, setImages] = useState([
      { title: 'Title1', src: Image1, open: false },
      { title: 'Title2', src: Image1, open: false },
      { title: 'Title3', src: Image1, open: false },
      { title: 'Title4', src: Image1, open: false },
      { title: 'Title5', src: Image1, open: false },
      { title: 'Title6', src: Image1, open: false },
      { title: 'Title7', src: Image1, open: false },
      { title: 'Title8', src: Image1, open: false },
      { title: 'Title9', src: Image1, open: false },
      { title: 'Title10', src: Image1, open: false },
      { title: 'Title11', src: Image1, open: false },
      { title: 'Title12', src: Image1, open: false },
      { title: 'Title13', src: Image1, open: false },
      { title: 'Title14', src: Image1, open: false },
    ]);
    
    // The you toggle function be like this:
    
    const toggle = e => {
      // Find image that was clicked
      const currentImage = images.find(image => (image.title = e.target.name));
      setImages(prevState => [
        // All Images in the previos image
        ...prevState,
        // get all the properties of cuurent image object, and set the open to opposite to what it was before
        { ...currentImage, open: !currentImage.open },
      ]);
    };
    
    // Then use map like this:
    {
      images.map((img, index) => (
        <Card>
          <CardImg1 src={Image1} onClick={toggle} />
          <CardDetails
            isOpen={isOpen}
            onClick={toggle}
            // THis name prop will be used to find the current image
            name={img.title}
          >
            ....
            ....
          </CardDetails>
        </Card>
      ));
    }
    
    
    // maybe to need to change this a bit according your your scenario, but this is the gist of it
    

    【讨论】:

    • TypeError: 无法读取未定义此行 { ...currentImage, open: !currentImage.open } 的属性“打开”,
    • 您需要检查e.target中的内容是否在右侧元素上使用onClick
    【解决方案3】:

    您在负责呈现图像列表的组件中具有切换状态。这种方法的一个缺点是,如果您有 10 张卡片并且想要切换第一张卡片,则由于状态发生变化,您正在重新渲染整个卡片列表。

    使用 react 的好处是构建的组件相互隔离,这样当组件的状态发生变化时,我们可以进行最少的渲染。

    您应该在CardDetails 组件内移动切换状态。这样,您就不再需要跟踪索引了,因为现在每个 CardDetails 组件都将拥有自己的切换状态。而且从现在开始 如果您正在切换卡片 - 1 它只会重新渲染它而不是其他卡片。

    如果您的浏览器中有 react 开发工具(如果没有,请安装它,因为它将帮助您进行调试)启用此 Highlight updates when components render 并将重新渲染与您当前的方法和我建议的方法进行比较。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-15
      • 2021-10-12
      • 2019-11-06
      • 2020-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多