首页 > 解决方案 > 需要帮助简化 Immutable.js 对象数组更新

问题描述

我是 immutablejs 的新手,并且设法更新了存储在对象数组中的对象的属性。我的目标是简化我的开发,但我觉得我让它变得更复杂了。显然,我错过了一些让这更简单的东西。

我创建了一个 stackblitz 项目,一个是没有 immutablejs https://stackblitz.com/edit/react-before-immutable的代码,一个是 immutablejs https://stackblitz.com/edit/react-after-immutable

(下面的代码也是)。

我在这里看到了一些示例,人们使用 findIndex 的第二个参数,但该函数从未被我调用过。它也不在文档中,所以我猜它不再受支持。

使用 Immutable.js

import React, { useState } from 'react';
import { List } from 'immutable';

export default () => {

  const init = [{
    id: 101,
    interestLevel: 1
  },
  {
    id: 102,
    interestLevel: 0
  }];

  const [myArray, setMyArray] = useState(init);

  const updateRow = (e) => {
    const id = parseInt(e.target.attributes['data-id'].value);

    const immutableMyArray = List(myArray);
    const index = List(myArray).findIndex((item) => {
      return item.id === id;
    });
    const myRow = immutableMyArray.get(index);
    myRow.interestLevel++;
    const newArray = immutableMyArray.set(index, myRow);

    setMyArray(newArray);


  };


  return (

    <ul>
      {
        myArray.map(function (val) {
          return (
            <li key={val.id}>
              <button onClick={updateRow} data-id={val.id}  >Update Title</button>
              {val.id} :  {val.interestLevel}
            </li>
          )
        })
      }
    </ul>

  )
}

没有 Immutable.js

import React, { useState } from 'react';

export default () => {

  const init = [{
    id: 101,
    interestLevel: 1
  },
  {
    id: 102, 
    interestLevel: 0
  }];

  const [myArray, setMyArray] = useState(init);

  const updateRow = (e) => {
    const id = e.target.attributes['data-id'].value;
    const newMyArray = [...myArray];
    var index = newMyArray.findIndex(a=>a.id==id);
    newMyArray[index].interestLevel = myArray[index].interestLevel + 1;
    setMyArray(newMyArray);
  }


  return (

    <ul>
      {
        myArray.map(function (val) {
          return (
            <li key={val.id}>
              <button onClick={updateRow} data-id={val.id}  >Update Title</button>
              {val.id} :  {val.interestLevel}
            </li>
          )
        })
      }
    </ul>

  )
}

标签: javascriptreactjsimmutable.js

解决方案


你考虑过 immutablejs 的目的吗?

在您的示例中,您只是在代码中添加了不必要的复杂性,而没有利用库提供的收益。

不可变的目的是提供不可变的集合,灵感来自 scala。换句话说,您创建了您的集合,然后将它传递给另一个组件,您可以确定没有元素被添加或删除。但是,个别元素不受此类保证,部分原因是 JS 带来的限制(或缺乏限制)。

正如您的代码中所代表的那样,做这样的事情的理由很少。为了展示如何做到这一点,我冒昧地更改了您的报价:

class Comp extends React.Component {

  constructor(props) {
    super(constructor);
    if (props.interests) {
      this.state = {
        interests: props.interests
      }
    } else {
      this.state = {
        interests: Immutable.Set([])
      }
    }
  }

  updateRow(e) {
    return function() {
      this.setState({
        interests: this.state.interests.update((elements) => {
          for (var element of elements) {
            if (element.id == e) {
              element.interestLevel++;
            }
          }
          return elements;
        })
      });
    }
  }


  render() {
    var interests = this.state.interests;
    var updateRow = this.updateRow;
    var list = this;
    //return (<div>Test</div>);
    return ( <
        ul > {
          interests.map(function(val) {
              return ( <
                  li key = {
                    val.id
                  } >
                  <
                  button onClick = {
                    updateRow(val.id).bind(list)
                  }
                  data-id = {
                    val.id
                  } > Update Title < /button> {
                  val.id
                }: {
                  val.interestLevel
                } <
                /li>
            )
          })
      } <
      /ul>

  )
}
}
var interests = Immutable.Set([{
    id: 1,
    interestLevel: 0
  },
  {
    id: 2,
    interestLevel: 0
  }
])
ReactDOM.render( < Comp interests = {
      interests
    }
    />, document.getElementById("app"));
<script src="https://cdn.jsdelivr.net/npm/immutable@4.0.0-rc.12/dist/immutable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0/umd/react-dom.production.min.js"></script>

<div id='app'></div>

变化:

  1. 将您的组件重写为一个类。这纯粹是为了突出其余的变化
  2. prop您的组件现在需要一个包含兴趣的外部组件。这意味着您可以传递 aSet并确保它不会在组件中突然添加元素
  3. 该组件负责利息水平。因此,每当您单击其中一个按钮时,都会在 上update调用该函数,该函数Set用于更新集合中的项目
  4. 整个事情通过render()

这既更具可读性,也更易于管理。


推荐阅读