如何更新一个复杂的数组?

时间:2018-10-04 19:22:29

标签: javascript reactjs

我处于这种状态

allVotes: [
  {
    id: "vote_1",
    title: "How is your day?",
    description: "Tell me: how has your day been so far?",
    choices: [
      { id: "choice_1", title: "Good", count: 7 },
      { id: "choice_2", title: "Bad", count: 12 },
      { id: "choice_3", title: "Not sure yet", count: 1 },
    ],
  },
  {
    id: "vote_2",
    title: "Programming languages",
    description: "What is your preferred language?",
    choices: [
      { id: "choice_1", title: "JavaScript", count: 5 },
      { id: "choice_2", title: "Java", count: 9 },
      { id: "choice_3", title: "Plain english", count: 17 },
    ],
  },
],

,并且需要更新计数。这可以(在控制器组件中)工作

registerVote(vote, choice) {
  this.setState(prevState => {
    return {
      allVotes: prevState.allVotes.map(
        pVote =>
          pVote.id !== vote.id
            ? pVote
            : {
                ...pVote,
                choices: pVote.choices.map(
                  pChoice =>
                    pChoice.id !== choice.id
                      ? pChoice
                      : {
                          ...pChoice,
                          count: pChoice.count + 1,
                        },
                ),
              },
      ),
    };
  });
}

但是它看起来很复杂,我不确定 如果这是正确的方法。有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

实际上,这是您要保持不变性的方法,但是可以通过使用一些辅助函数来简化它:

 const change = (key, fn) => obj => ({ ...obj, [key]: fn(obj[key]) });
 const changeOne = (filter, fn) => arr => arr.map(el => filter(el) ? fn(el) : el);

 this.setState(change("allVotes", changeOne(v => v.id === vote.id, change("count", c => c + 1))));

答案 1 :(得分:2)

您可以将组件分解为较小的组件。说:形式,票数,票数。

class Vote extends React.Component {
    increment = () => {
        this.setState(prevState => ({
            count: prevState.count + 1
        }), this.onItemChange);
    }

    onItemChange = () => {
        this.props.onItemChange(this.state, this.props.id);
    }
}


class Votes extends React.Component {
    onItemChangedCallback = (itemToUpdate, idToUpdate) => {
        this.setState(prevState => ({
            allVotes: prevState.allVotes.map(vote => vote.id === idToUpdate? {...itemToUpdate}: vote; )
        }), this.onVotesChangeCallback);
    }

    onVotesChangeCallback = () => {
        this.props.onVotesChange(this.state.allVotes)
    }

    render() {
        return (<div>this.state.allVotes.map(vote => <Vote id={vote.id} key={vote.id} vote={vote} onItemChange={this.onItemChangedCallback} />)</div>);
    }
}

此外,这意味着更多的类/组件符合“单一职责”原则:因此Votes处理列表中的移动元素,删除并添加新的但不包括时间戳值,投票者数量或投票者列表的元素。 Vote处理单个项目。等等。更好的测试,更易于阅读,更易于在不同上下文中重用。

[UPD]经过更多思考之后,我认为最好将唯一的id从投票传递到投票,而不是位置索引(以及key道具建议)。然后使用它的id找出应该替换哪个collection的元素。相应地更新了代码段。

[UPD2]我猜Vote可以是功能/无状态组件,但我最好将其保留为基于类的,以使想法更易于理解