2016-12-07 61 views
2

Cam Jackson,我们应该使用终极版,写小,无状态的,功能组件。这里有一个例子:纯功能如何处理事件反应的组分

const ListView = ({items}) => (
    <ul> 
     {items.map(item => <ItemView item={item}/>)} 
    </ul> 
) 

const ItemView = ({item}) => (
    <li><a>{item.name}</a></li> 
) 

现在,假设你想要处理鼠标点击,并触发一个采取被点击项目的动作。我觉得这是一个很不错的办法做到这一点:

const ListView = ({items, onItemClicked}) => { 
    const _onClick = item => event => { 
     event.preventDefault() 
     onItemClicked(item) 
    } 
    return (
     <ul> 
      {items.map(item => <ItemView item={item} onClick={_onClick(item)}/>)} 
     </ul> 
    ) 
} 

const ItemView = ({item, onClick}) => (
    <li><a onClick={onClick}>{item.name}</a></li> 
) 

然而,根据Esa-Matti Suuronen,这是一个反模式,这将导致性能损失。

很明显,可以处理ItemView组件内的事件,并注入item。但是,如果我们想避免在渲染函数内部创建函数,那么我们需要将它变成一个类组件。

这是一个很常见的模式,我想找到一个简单的方法来处理这个问题,有功能部件,不会造成性能问题。你有什么建议?

如果没有办法做到这一点,我将无法在所有使用功能组件。因为我经常想到,在某些时候,我需要将每个功能组件转换为一个类。

+0

您可以将'_onClick'移到函数之外 - 这样它仍然在范围内,但是每次组件呈现时都不会重新初始化。也就是说,在那个时候,把它变成一个班级可能会更清洁。 –

+0

不可以。您错过了这一点。首先,你不能这样做,因为它引用了'onItemClicked'道具。当然你可以通过它。但重点是它每次都会创建一个新的_bound_函数。注意'_onClick'是一个函数,它返回一个函数(我猜它叫做高阶函数)。由于'ItemView'每次都获得一个新的道具,这将打破“纯粹渲染”的优化。问题是如果有一种方法可以在不使用类的情况下进行这项工作。 – Ropez

+0

道歉,我不应该有我的早晨咖啡之前评论!在这种情况下,我不确定解决方案。 –

回答

1

在做了更多的思考之后,我想我已经找到了解决问题的方法。我意识到我们需要更多的Redux容器。不仅用于主要顶级组件,还用于可重用的子组件。

上面的例子可以解决这样的:

const ListView = ({items, onItemClicked}) => (
    <ul> 
     {items.map(item => <ItemContainer item={item} onItemClicked={onItemClicked}/>)} 
    </ul> 
) 

const ItemView = ({item, onClick}) => (
    <li><a onClick={onClick}>{item.name}</a></li> 
) 

const mapDispatch = (dispatch, {item, onItemClicked}) => ({ 
    onClick: (event) => { 
     event.preventDefault() 
     onItemClicked(item) 
    } 
}) 

const ItemContainer = connect(null, mapDispatch)(ItemView) 

在很多情况下,我们将不再需要从外部组件传递一个回调到内的,因为我们将能够直接派遣行动来自ItemContainer

+0

这不是有同样的问题吗?每次调用mapDispatch时,都会将一个新函数传递给onClick属性。 –

+0

'mapDispatch'在组件每次接收新道具时调用(在这种情况下'item',假设'onItemClicked'不变)。在这种情况下,我们期望组件重新呈现,因为它代表了一个新项目。在原始示例中,每次更改任何单个项目时,都会重新呈现_all_“ItemView”。 – Ropez

0

通过onItemClicked功能作为ItemView上的道具并将其用作onClick函数。在onItemClicked实施有它收到一个事件,并获得item关闭事件。

<ItemView item={item} onItemClicked={onItemClicked}/> 

const ItemView = ({item, onItemClicked}) => (
    <li><a item={item} onClick={onItemClicked}>{item.name}</a></li> 
) 
+0

好的,谢谢你的建议,但它实际上并没有回答如何从项目中取消项目的问题。 – Ropez

+0

const item = event.target.item – sjc42002