我的用户在此页面上有一些数据:
[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}]
Apollo查询加载此数据。用户可以使用表单向页面添加名称或从页面中删除名称。 Apollo变异处理添加或删除请求。在变异之后调用RefetchQueries,更新状态并重新呈现名称列表。
问题是,如果我添加一个名称,refetchQueries将返回所有4个对象,作为回报,所有4个对象都设置为state。
[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}, { name: 'Mary', id: 4 }]
我想了解如何区分新数据和旧数据。然后从状态数组中添加或删除正确的对象,而不是完全重置状态。使用的ID将始终是唯一的。
loadData = (names, that) => {
that.setState({ loading:true });
let data = {};
data.names= [];
const oldNames = that.state.names;
names.map(name=> (
data.names.push({ name: name.name, id: name.id })
));
that.setState({names: data.names, loading: false });
}
上面的函数在componentWillUpdate中被调用,如下所示:
componentWillUpdate(nextProps, nextState) {
loadData(nextProps.names, this);
}
我正在尝试更改此功能,如下所示:
updateData = (names, that) => {
let data = {};
data.names = [];
const oldNames = that.state.names ;
names.map(name => (
data.names.push({ name: name.name, id: name.id })
));
let difference = _(data.names)
.differenceBy(oldNames, 'id', 'name')
.map(_.partial(_.pick, _, 'id', 'name'))
.value();
if (data.names.length > oldNames.length)
that.setState(prevState => ({
names: [...prevState.names, {name: difference[0].name, id: difference[0].id}]
}))
}
但是以这种方式找到旧数据和新数据之间的差异并不是很好。我已尝试过Compare 2 arrays which returns difference的解决方案,但我无法让它发挥作用。我希望你能帮我介绍一个更好的方法来找到差异。在上面的示例中,我使用了lodash,但这不是必需的。我也想知道是否有更好的方法。例如,直接从Apollo变异中获取结果并将此结果添加到State。
UPDATE节点映射:
render() {
if (this.state.loading) { return <div>Loading...</div> }
const links = this.state.links.map( (link,i) => {
return (
<Link
linkClass={this.props.linkClass}
key={link.target+i}
data={link}
/>);
});
const nodes = this.state.nodes.map( (node) => {
return (
<Node
nodeClass={this.props.nodeClass}
data={node}
label={node.label}
key={node.id}
onClick={this.onClickHandler.bind(this, node)}
/>);
});
return (
<div className="graphContainer">
<svg className="graph" width={FORCE.width} height={FORCE.height}>
<g >
{links}
</g>
<g >
{nodes}
</g>
</svg>
</div>
);
}
}
答案 0 :(得分:1)
当你调用this.setState({ names: newArray })
时,newArray
必须是一个新构造的数组(因为你不能直接改变状态),所以无论你是否基于它构造这个数组都没有区别。区别或只是使用API调用的结果。
换句话说,setState({ names: [1, 2, 3] })
或setState({ names: [...someOldState, 3] })
之间没有区别,因为在这两种情况下您仍然将names
设置为新构建的数组,因此您尝试计算这种差异无论如何都无助于你的意图。
React优化仅使用更改的密钥重新渲染组件,因此您只需确保映射组件中提供了unique and stable密钥。
此优化是在虚拟DOM级别完成的。如果您想避免在未更改的render
和Link
组件中调用Node
,则需要将它们声明为PureComponent
,或者使用shouldComponentUpdate
函数进行调用道具不浅。