如何只修改 react .map 函数中的一个元素?

Posted

技术标签:

【中文标题】如何只修改 react .map 函数中的一个元素?【英文标题】:How to modify only one element in a react .map function? 【发布时间】:2017-11-09 15:59:03 【问题描述】:

我对反应有点陌生,对在这里做什么有点迷茫。我正在从 firebase 加载数据并使用 .map 函数渲染该对象的道具,以列出页面上的所有“cmets”,效果很好。我还想调用一个组件,允许用户回复单个评论(即地图中的一个特定元素),但正如这段代码所预期的那样,当点击回复按钮时,它会在每个元素下显示被调用的组件地图,这是不可取的。在这种情况下,无论如何我可以只为地图的一个元素调用组件吗?

changeIsReply() 
  this.setState(
    isReply: !this.state.isReply,
  );
    

  render() 

  return (
    <div>
    <ul className="list-group">
    Object.values(this.props.commentInfo).map((data) =>
      data.map((secondData, i) =>
        <div className="commentHolder" key=i>
            <p>secondData.text</p>
            <p>secondData.category</p>
            <p>secondData.organization</p>
            <button> UpButton </button> <br />
            <button> DownButton </button>
            <button onClick = this.changeIsReply > Reply </button>
            this.state.isReply ? <SetComment id=secondData.key /> : null
        </div>
      )
    )
    </ul>
    </div>
  )

【问题讨论】:

【参考方案1】:

那是因为您对所有 cmets 使用单一状态。

<button onClick = () => this.changeIsReply(secondData.key) > Reply </button>

this.state.isReply && this.state.clickedComment == secondData.key ? <SetComment id=secondData.key /> : null

并将您的 changeIsReply() 更改为:

changeIsReply(clickedId) 
    this.setState(
        isReply: !this.state.isReply, 
        clickedComment: clickedId
    );

看看这是否有效。不要忘记将新状态添加到您的构造函数中。

【讨论】:

【参考方案2】:

您需要将 isReply 保留为数组数组,并根据单击的评论的索引,仅更新正确的值,例如

state= 
   isReply: [[]]

changeIsReply(i, j) 
  var isReply = [...this.state.isReply]
  if(isReply[i] === undefined) 
    isReply.push([true]) = 
   else 
    if(isReply[i][j] === undefined) 
      isReply[i].push(true)
     else 
       isReply[i][j] = !isReply[i][j]
    
  
  this.setState(
    isReply
  );
    

  render() 

  return (
    <div>
    <ul className="list-group">
    Object.values(this.props.commentInfo).map((data, i) =>
      data.map((secondData, j) =>
        <div className="commentHolder" key=j>
            <p>secondData.text</p>
            <p>secondData.category</p>
            <p>secondData.organization</p>
            <button> UpButton </button> <br />
            <button> DownButton </button>
            <button onClick = () => this.changeIsReply(i, j) > Reply </button>
            this.state.isReply[i][j] ? <SetComment id=secondData.key /> : null
        </div>
      )
    )
    </ul>
    </div>
  )

【讨论】:

【参考方案3】:

您可以跟踪哪个评论应该有 SetComment 组件。

constructor(props) 
  super(props);
  this.state = 
    // init commentReplyIds as empty array
    commentReplyIds : [],
    // ... rest of your state
  


changeIsReply(commentId) 
  const newCommentReplyIds = [...this.state.commentReplyIds. commentId];
  this.setState(
    commentReplyIds: newCommentReplyIds
  );
    

  render() 
  // in here I am using the data.text as the unique id of each comment, you can use other serializable value.
  return (
    <div>
    <ul className="list-group">
    Object.values(this.props.commentInfo).map((data) =>
      data.map((secondData, i) =>
        <div className="commentHolder" key=i>
            <p>secondData.text</p>
            <p>secondData.category</p>
            <p>secondData.organization</p>
            <button> UpButton </button> <br />
            <button> DownButton </button>
            <button onClick = () => this.changeIsReply(secondData.text) > Reply </button>
            this.state.commentReplyIds.includes(secondData.text) ? <SetComment id=secondData.key /> : null
        </div>
      )
    )
    </ul>
    </div>
  )

通过这种方法,您可以拥有多个SetComment 组件,位于用户单击了回复评论按钮的不同cmet 中。

【讨论】:

【参考方案4】:

我建议把它分成两个部分。 CommentListComment 组件。

comment-list.js

import Comment from './comment';

class CommentList extends Component
    render()
    return(
        <div>
        <ul className="list-group">
                Object.values(this.props.commentInfo).map((data) =>
                data.map((secondData, i) =>
                    <Comment text=secondData.text category=secondData.category organization=secondData.organization key=secondData.key />
      )
        </ul>
      </div>
    )
  

comment.js

class Comment extends Component 
    constructor(props)
    super(props);
    this.state = 
        isReply: false
    
  
  changeIsReply = () => 
    this.setState(
      isReply: !this.state.isReply,
    );
     
    render()
    const text, category, organization, key = this.props;
    return(
      <div className="commentHolder" key=i>
        <p>text</p>
        <p>category</p>
        <p>organization</p>
        <button> UpButton </button> <br />
        <button> DownButton </button>
        <button onClick = this.changeIsReply > Reply </button>
        this.state.isReply ? <SetComment id=key /> : null
      </div>
    )
  


export default Comment;

这样,每个评论都可以控制自己的状态以及是否显示SetComment 组件。 尝试制作更多组件,而不是将所有标记放在单个渲染方法中。这也有助于组织您的代码,以便您将每组值映射到一个组件,我觉得这让您更容易理解。

【讨论】:

以上是关于如何只修改 react .map 函数中的一个元素?的主要内容,如果未能解决你的问题,请参考以下文章

js map的使用

如何修复 React 中的“TypeError:categories.map 不是函数”错误

JS中的map()函数

JavaScript Map –如何使用JS.map()函数

React,如何从同一个组件访问我的渲染函数中的 DOM 元素

如何仅从 React 中的 API 获取第一个数据?