【问题标题】:Javascript array map function keeps records of previous items of arrayJavascript数组映射函数保留数组先前项的记录
【发布时间】:2017-12-21 01:38:49
【问题描述】:

更新好的,所以我注意到,即使在 isCategoryActive() 函数中,我只改变了变量 newCategories,它被分配了来自 @ 的值987654323@ searchCategories 属性也会改变值,因此将其传递给连续数组项对isCategoryActive 函数的调用。为什么会这样??更新

我正在基于 Wordpress REST API 在 React 中构建博客前端,但在检查帖子类别是否已被过滤后,我在创建链接以过滤帖子类别时遇到问题。我遇到的问题是,即使我在 map 函数中编写了一个纯函数isCategoryActive,每个连续的类别链接 url 中都有每个前面的类别 id。我原以为每次调用纯函数时都会收到一个干净的结果,但在我的情况下并非如此。目前 wordpress 存储 3 个类别: “未分类”,ID:1, id 为 4 的“javascript”, “第三类”,id:10

我试图让 render() 函数中的 console.log(newCategories, url) 函数记录:

[1] 博客?categories=1
[4] 博客?categories=4
[10] 博客?categories=10

但目前它会记录:

[1] 博客?categories=1
[1,4] 博客?categories=1,4
[1,4,10] blog?categories=1,4,10

我不知道它为什么要记录以前的类别 ID。

代码如下:

// import dependencies
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import axios from 'axios'

// import components
import '../Styles/Css/PostsCategories.css'

import { createSearchUrl } from './SharedModules'

class PostsCategories extends Component {
  constructor() {
    super()
    this.state = {
      categories: null,
      loading: false
    }
  }

  componentDidMount() {
    this.setState({
      loading: true
    })
    axios.get(`http://localhost/wordpress-api/wp-json/wp/v2/categories`)
      .then(res => {
        this.setState({
          categories: res.data,
          loading: false
        })
      })
  }

  isCategoryActive = (category) => {
    let newCategories = this.props.searchCategories
    newCategories.indexOf(category) === -1
    ? newCategories.push(category)
    : newCategories.splice(newCategories.indexOf(category),1)
    return newCategories
  }

  render() {
    if (this.state.loading || !this.state.categories) return <div className='posts-categories'><h2 className='loading'>Loading ...</h2></div>

    const categories = this.state.categories.map(category => {
      const newCategories = this.isCategoryActive(category.id)
      const url = createSearchUrl('/blog', newCategories, this.props.searchString)
      console.log(newCategories, url)
      return (
        <Link
          to={url}
          onClick={this.props.searchCategoryChange.bind(this, category.id)}
          className='posts-category'
          key={category.id} >
            {category.name}
        </Link>
      )})

    return (
      <div className='posts-categories'>
        {categories}
      </div>
    )
  }
}

export default PostsCategories

【问题讨论】:

    标签: javascript arrays reactjs dictionary pure-function


    【解决方案1】:

    根据我发现的 更新 中的新信息,我已将 isCategoryActive 函数修改为:

    isCategoryActive = (category) => {
        let newCategories = []
        this.props.searchCategories.map(category => newCategories.push(category))
        newCategories.indexOf(category) === -1
        ? newCategories.push(category)
        : newCategories.splice(newCategories.indexOf(category),1)
        return newCategories
      }
    

    现在它运行良好。但是,我仍然不完全理解它为什么要存储以前的记录。我想我错过了一些非常愚蠢的事情,但如果有人能向我描述一下从根本上出了什么问题,那就太好了。

    【讨论】:

      【解决方案2】:

      在你原来的函数里面是这样的:

      let newCategories = this.props.searchCategories
      

      这实际上不会复制searchCategories,而是引用它。它们都指向同一个数组,这就是为什么原来的searchCategories 数组也被修改了。

      当您映射 searchCategories 数组时(就像您在自己的解决方案中所做的那样),您正在构建一个新数组(使用 push 语句)而不修改 searchCategories 数组。然而,这是制作数组副本的一种非常复杂的方式。

      【讨论】:

      • 很高兴认识@shubham 和 snwclone。谢谢。我的另一个问题是,为什么它引用道具而不是赋值?它这样做是因为我们在一个类中操作并且它改变了它吗?您是否愿意分享一些关于一个值何时引用另一个值以及何时分配其值的信息?
      • 与类内操作无关。我能找到的最好的解释是this SO question
      • 好的。我现在明白了。非常感谢。奇怪的是我以前从来没有遇到过这样的问题。
      【解决方案3】:

      问题是你在分配时直接改变this.props.searchCategories

      let newCategories = this.props.searchCategories
      

      它是通过引用分配的

      您需要创建一个新对象而不是直接分配它。为此,您可以使用扩展运算符而不是映射道具 array 并将项目推送到 newCategories 数组。

      isCategoryActive = (category) => {
          let newCategories = [..this.props.searchCategories]
          newCategories.indexOf(category) === -1
          ? newCategories.push(category)
          : newCategories.splice(newCategories.indexOf(category),1)
          return newCategories
        }
      

      【讨论】:

      • Javascript 分配是通过引用完成的,所以当你这样做时 let newCategories = this.props.searchCategories 因此你通过引用分配道具并修改 newCategories 修改道具 searchCategories
      【解决方案4】:

      代替

      let newCategories = this.props.searchCategories
      

      你可以写成

      let newCategories = this.props.searchCategories.splice();
      

      这将创建一个新对象。

      默认情况下,JavaScript 仅在我们直接分配对象(以及数组)时复制引用。那就是当新的Object改变时,Original也会改变。

      您必须使用 map、splice 或 Object.assign 来创建新对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-05
        • 1970-01-01
        • 2017-01-19
        • 1970-01-01
        • 2019-12-10
        • 2012-10-09
        • 2011-02-15
        相关资源
        最近更新 更多