需要帮助以简化对象的Immutable.js更新

时间:2018-12-24 22:25:51

标签: javascript reactjs immutable.js

我是immutablejs的新手,并且设法更新了存储在对象数组中的对象的属性。我的目标是简化我的开发,但是我觉得自己变得更加复杂。显然,我缺少使它更简单的东西。

我创建了要堆叠的项目,一个使用不带有immutablejs https://stackblitz.com/edit/react-before-immutable的代码,另一个使用不可变的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>

  )
}

2 个答案:

答案 0 :(得分:0)

您是否考虑过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。这意味着您可以传递Set并确保它不会在组件中添加蓝色的元素
  3. 该组件负责利息水平。这样,每当您单击其中一个按钮时,就会在update上调用Set函数,该函数用于更新集合中的项目
  4. 整个事物通过render()呈现为数组

这既可读性强又易于管理。

答案 1 :(得分:0)

如本comment中所述,您正在寻找使用Immutable.js在深层对象层次结构中更新对象的简便方法。

updateIn应该可以解决问题。

const immutableObject = Immutable.fromJS({ outerProp: { innerCount: 1 } });
immutableObject.updateIn(['outerProp', 'innerCount'], count => count + 1);

还值得注意的是,您可能想调用Immutable.fromJS()而不是使用Immutable.List(),因为后者不会将您的JavaScript对象深深地转换为不可变对象,如果您使用重新假设数据结构是完全不变的。将上面的代码切换为使用Immutable.fromJS()updateIn,我们得到:

// In updateRow
const immutableMyArray = fromJS(myArray);
const index = immutableMyArray.findIndex((item) => {
  return item.id === id;
});
const newArray = immutableMyArray.updateIn([index, 'interestLevel'], interestLevel => interestLevel + 1);

setMyArray(newArray);
相关问题