2016-12-07 65 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