React:如何比较当前的props.children和新的props.children

时间:2015-02-28 16:31:24

标签: javascript compare reactjs

您好,

我正在构建仅作为其他一些生成内容的包装器并使用第三方库的组件。此库与props.children组件一起使用。到目前为止一切都那么好,但这个四方派对库在应用或刷新元素时有点迟钝。并且因为只有在props.children更改this.props.children时才刷新此库的原因,我想知道如何比较nextProps.children中的shouldComponentUpdatestate.listName。我当时认为PureRenderMixin应该做的工作,但对我来说它不起作用。即使我仅在下面的示例中更改<div> List name '{this.state.listName}' <br /> <MyComponent> <ul> {listOfLi} </ul> </MyComponent> </div> ,也会重新呈现组件。

props.children

有没有办法,如何管理{{1}}的比较或任何其他选项如何做这样的事情? 谢谢你的帮助!

3 个答案:

答案 0 :(得分:4)

你可以利用儿童key道具,反应建议应该给予儿童阵列以唯一地识别它们。因为每个孩子都有一把钥匙,你可以可靠地判断孩子是否在道具变化中发生了变化(这是钥匙的整个点!)。

React.render(<App><Child key='1'/><Child key='2'/></App>, document.body)

并在每次更新之前检查要检查的应用程序组件(如果孩子已更改

shouldComponentUpdate(nextProps){
   var oldKeys = this.props.children.map( child => child.key);
   var newKeys = nextProps.children.map( child => child.key);

   //compare new and old keys to make sure they are the same
}

作为更进一步的优化,我们知道孩子永远不会因状态变化而改变,所以我们实际上可以在componentWillReceiveProps()进行比较,只需设置一些状态属性,如childrenHaveChanged

答案 1 :(得分:2)

关于您描述的设计和行为的某些东西已经关闭。如果有的话,您几乎不必担心自己执行children的手动差异。那应该留给React。如果您使用的库在每次组件更新时都在阻塞,无论是由于children还是其他状态/属性更改而引起的,它都不会以被动方式编写,因此您应该寻找一种以被动方式编写的程序。或者,您可以通过打开一个问题或提交一个拉取请求,为修复开放源代码项目中的这种行为做出贡献。

要做您想做的事情并不容易,因为它没有必要。 React非常擅长处理对帐,并且仅在实际发生更改的情况下才会渲染,该更改会更改与之相关的DOM状态。

答案 2 :(得分:0)

正如 Matt S 所指出的那样,可接受的答案是一种脆弱的解决方法,它取决于key的非标准用法。除了他列出的清单示例之外,如果您的key={id}保持不变,但某些字段在其表示的资源中被修改,则即使使用id之类的东西也会掉线。

issue包含对该主题的精彩讨论,并以更稳定的workaround结尾。本质上,您可以简化children道具,使其可以进行深度比较。您可以使用React.Children实用程序来编写简化方法:

// Flattens all child elements into a single list
const flatten = (children, flat = []) => {
    flat = [ ...flat, ...React.Children.toArray(children) ]

    if (children.props && children.props.children) {
        return flatten(children.props.children, flat)
    }

    return flat
}

// Strips all circular references and internal fields
const simplify = children => {
    const flat = flatten(children)

    return flat.map(
        ({
            key,
            ref,
            type,
            props: {
                children,
                ...props
            }
        }) => ({
            key, ref, type, props
        })
    )
}

然后,您可以使用shouldComponentUpdateReact.memo来阻止重新渲染:

const MyComponent = ({ children }) => (
    <div>{ children }</div>
)

export default React.memo(MyComponent, (prev, next) => (
    JSON.stringify(simplify(prev.children)) ===
    JSON.stringify(simplify(next.children))
))

这些实用程序+ JSON.stringify只是一种方法,the comment中提到的方法与此类似,您也可以利用lodash.isequal之类的实用程序进行深度比较。不幸的是,我不知道有一个或两个班轮可以进行这种比较,但是如果您知道一种更简单,更稳定的方法,请发表评论!