【问题标题】:How to identify a single div element among set of elements in react?如何在反应中识别一组元素中的单个div元素?
【发布时间】:2019-09-11 07:40:34
【问题描述】:

我有一个带有 Div 元素列表的反应应用程序来创建一些卡片。每张卡片都有“阅读更多”按钮来展开和折叠一个段落,每次鼠标点击我都会切换它。 我的问题是,对于每次点击,它会展开所有卡片中的段落,而不是我点击的卡片中的段落。所以我无法识别点击的(这张)卡片

组件:

class BidCard extends Component {
    constructor(props) {
        super(props);
        this.state = {
            readMoreOpen: false,
        }
    }

    readMore() {
        this.setState({ readMoreOpen: !this.state.readMoreOpen })
    }

    render() {

        const { articles } = this.props;

        return (
            articles.map(article => {
                return (
                    <div className="projectCardRoot" key={article.id}>
                        <div className="projectCardMainLogin">
                            <div className="projectCardMiddle">
                                <p className={this.state.readMoreOpen ? 'openFullParagraph' : 'closeFullParagraph'} id="projectCardDesc">{article.description}</p>
                                <div className="cardReadMore desktopDiv" onClick={this.readMore.bind(this)}>Read more</div>
                            </div>
                        </div>
                    </div>
                )
            })
        )
    }
}

export default BidCard;

我该如何解决这个问题?

【问题讨论】:

  • 可以同时展开多少张卡片?
  • 也许使用另一个只有 1 张卡的组件。所以你有这个组件BidCardsarticles.map(article =&gt; { return ( &lt;div className="projectCardRoot" key={article.id}&gt; &lt;BidCard props here /&gt;&lt;/div&gt;)}) 内部,并将 readMoreOpen 方法作为道具传递。并且不要为每张卡使用相同的 ID。您可以为 1 张卡制作 const 组件。不是类组件。
  • @RohanAgarwal 只有一张卡
  • 然后,不是将关闭/打开卡片的逻辑保留在 BidCard 组件中,而是将其保留在父组件之外,并从那里控制它。

标签: javascript html css reactjs


【解决方案1】:

您可以将扩展卡的id保存到状态并在渲染项目时检查它:

class BidCard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      readMoreOpen: [],  // Use array here
    }
  }

  // Add card id to the expanded array if not already there, otherwise remove it
  readMore = (id) => {
    this.setState(state => {
      if (state.readMoreOpen.includes(id)) {
        return {readMoreOpen: state.readMoreOpen.filter(readId => readId !== id)}
      }
     return {readMoreOpen: [...state.readMoreOpen, id]}
    })
  }

  render() {

    const { articles } = this.props;

    return (
      articles.map(article => {
        return (
          <div className="projectCardRoot" key={article.id}>
            <div className="projectCardMainLogin">
              <div className="projectCardMiddle">
                {/*Check if the item is in expanded items array */}
                <p className={this.state.readMoreOpen.includes(article.id) ? 'openFullParagraph' : 'closeFullParagraph'} id="projectCardDesc">{article.description}</p>
                <div className="cardReadMore desktopDiv" onClick={() => this.readMore(article.id)}>Read more</div>
              </div>
            </div>
          </div>
        )
      })
    )
  }
}

【讨论】:

  • 这里的简单映射应该足够了this.props.articles.map(article =&gt; article.id === id ? true : false) - 包括+过滤器+扩展运算符似乎太多数组操作:)
  • 嗯,有趣的方法,但是现在您将状态(我使用的是状态,而不是道具)设置为布尔数组,所以下次您无法将其与 id 进行比较.
  • 在这种情况下,我只会在状态中保留扩展文章 id 的字符串,不需要保留整个数组:D。顺便说一句,从道具中使用数组更安全 - 更防弹
  • 是的,我的解决方案更适合您想要扩展多个项目的情况。
  • 对于展开的多个项目,我会将展开方法移动到子组件:)
【解决方案2】:

您需要为每张卡片保持展开状态。 我建议为卡片创建组件

            articles.map(article => {
                return (
                    <Article key={article.id} {...article} />
                )
            })
        )
 class Article extends Component {

 state = {
   readMoreOpen: false 
 }

 readMore() {
        this.setState(state => ({ readMoreOpen: !state.readMoreOpen }))
    }

 render () {
  const {description} = this.props;
  return (<div className="projectCardRoot" >
                        <div className="projectCardMainLogin">
                            <div className="projectCardMiddle">
                                <p className={this.state.readMoreOpen ? 'openFullParagraph' : 'closeFullParagraph'} id="projectCardDesc">{description}</p>
                                <div className="cardReadMore desktopDiv" onClick={this.readMore.bind(this)}>Read more</div>
                            </div>
                        </div>
                    </div>)
}

}

其他方法是保留布尔数组,其中包含当前应扩展哪个文章 div 的信息,在此方法中,您需要使用扩展文章的 id 更新状态

readMore(id) {
  this.setState({ articles: this.props.articles.map(article => article.id === id ? true : false) } )
}

如果应该扩展,则在渲染中使用来自状态的布尔值作为信息

【讨论】:

    【解决方案3】:

    那是因为你所有的卡片目前共享相同的事实来源。您使用三元运算符来确定 Card 根据状态值将具有的类。好吧,所有卡都使用相同的状态值进行比较,所以可以理解,如果一个受到影响,那么所有卡也会受到影响。

    解决此问题的方法不止一种,但最合适的方法可能是创建一个单独的卡片组件。这使得每个 Card 组件都有自己的状态来跟踪。

    查看工作沙箱:https://codesandbox.io/s/quizzical-mahavira-wz8iu

    Parent.js

    import React from "react";
    import ReactDOM from "react-dom";
    import Card from "./Card";
    
    import "./styles.css";
    
    class BidCard extends React.Component {
      render() {
        const { articles } = this.props;
    
        return articles.map(article => {
          return <Card article={article} />;
        });
      }
    }
    
    BidCard.defaultProps = {
      articles: [{ description: "woof" }, { description: "meow" }]
    };
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<BidCard />, rootElement);
    

    Card.js

    import React, { useState } from "react";
    
    const Card = ({ article }) => {
      const [readOpen, setReadOpen] = useState(false);
      return (
        <div className="projectCardRoot" key={article.id}>
          <div className="projectCardMainLogin">
            <div className="projectCardMiddle">
              <p
                className={readOpen ? "openFullParagraph" : "closeFullParagraph"}
                id="projectCardDesc"
              >
                {article.description}
              </p>
              <div
                className="cardReadMore desktopDiv"
                onClick={() => setReadOpen(!readOpen)}
              >
                Read more
              </div>
            </div>
          </div>
        </div>
      );
    };
    
    export default Card;
    

    【讨论】:

      【解决方案4】:

      我对您的代码做了一些修改。这样它应该可以工作。

      我添加了解释这些变化的 cmets。主要思想是您不应该简单地存储布尔值readMoreOpen 状态(在您的代码中被视为一种在所有卡之间共享的状态),而是特定的卡身份。

      如果任何时候都只能有一张“扩展”卡,我的更改就会起作用。如果您的设计假设可能同时有几张“扩展”卡牌,那么解决方案会更加复杂,但并不多。

      class BidCard extends Component {
          constructor(props) {
              super(props);
      
              //  the way you've tried to keep status (open/closed) it wasn't tied to any speciifc card
              //  you should store this specific card instead
              this.state = {
                  //readMoreOpen: false,
                  expandedCard: null,
              }
              this.readMore = this.readMore.bind(this);
          }
      
          readMore(article) {
              //this.setState({ readMoreOpen: !this.state.readMoreOpen })
              this.setState({expandedCard: article})
          }
      
          render() {
      
              const { articles } = this.props;
              const { expandedCard } = this.state;
      
              return (
                  articles.map(article => {
                  //  the look of each card depends on state.expandedCard only if article == expandedCard it's shown with 'openFullParagraph' class
                  return (
                          <div className="projectCardRoot" key={article.id}>
                              <div className="projectCardMainLogin">
                                  <div className="projectCardMiddle">
                                      <p className={article == expandedCard ? 'openFullParagraph' : 'closeFullParagraph'} id="projectCardDesc">{article.description}</p>
                                      <div className="cardReadMore desktopDiv" onClick={() => this.readMore(article)}>Read more</div>
                                  </div>
                              </div>
                          </div>
                      )
                  })
              )
          }
      }
      
      export default BidCard;
      

      【讨论】:

        猜你喜欢
        • 2018-03-30
        • 1970-01-01
        • 2017-06-30
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 2023-03-03
        • 2012-09-19
        相关资源
        最近更新 更多