2016-03-31 16 views
3

material-uiを使用してthe new Material Design Google Contacts(材料デザインスキンを有効にする必要があります)のように機能する連絡先リストを実装しようとしています。
具体的には、行ホバー上にアバターの代わりにチェックボックスを表示しようとしています。
興味のある行だけをキャッチして再描画して、それに応じてアバター/チェックボックスを表示したいと思っています。これは簡単な作業ですが、レンダリングされた行をレンダリングすることはできません(リスト全体を再レンダリングするのではなく) このようなことをどうやって行うべきか提案はありますか?リスト全体を再レンダリングせずにリストの1行を再描画する

この一時的な解決方法では、テーブルを扱うコンテナコンポーネントが使用されます。 行が移動されると、TableコンポーネントのonRowHoverから取得し、コンテナ状態で保存します。これにより、リスト全体の再レンダリングがトリガされ、パフォーマンスは非常に悪くなります。

問題のビデオはhereです。ここで

は、コードサンプルです:

import React from 'react' 
import Avatar from 'material-ui/lib/avatar' 
import Checkbox from 'material-ui/lib/checkbox' 
import Table from 'material-ui/lib/table/table' 
import TableHeaderColumn from 'material-ui/lib/table/table-header-column' 
import TableRow from 'material-ui/lib/table/table-row' 
import TableHeader from 'material-ui/lib/table/table-header' 
import TableRowColumn from 'material-ui/lib/table/table-row-column' 
import TableBody from 'material-ui/lib/table/table-body' 
import R from 'ramda' 

export default class ContactsList extends React.Component { 

    constructor (props) { 
    super(props) 
    this.state = { hoveredRow: 0 } 
    this.contacts = require('json!../../public/contacts.json').map((e) => e.user) // Our contact list array 
    } 

    _handleRowHover = (hoveredRow) => this.setState({ hoveredRow }) 

    _renderTableRow = ({ hovered, username, email, picture }) => { 
    const checkBox = <Checkbox style={{ marginLeft: 8 }} /> 
    const avatar = <Avatar src={picture} /> 
    return (
     <TableRow key={username}> 
     <TableRowColumn style={{ width: 24 }}> 
      {hovered ? checkBox : avatar} 
     </TableRowColumn> 
     <TableRowColumn>{username}</TableRowColumn> 
     <TableRowColumn>{email}</TableRowColumn> 
     </TableRow> 
    ) 
    } 

    render =() => 
    <Table 
     height='800px' 
     fixedHeader 
     multiSelectable 
     onRowHover={this._handleRowHover} 
    > 
     <TableHeader displaySelectAll enableSelectAll> 
     <TableRow> 
      <TableHeaderColumn>Nome</TableHeaderColumn> 
      <TableHeaderColumn>Email</TableHeaderColumn> 
      <TableHeaderColumn>Telefono</TableHeaderColumn> 
     </TableRow> 
     </TableHeader> 
     <TableBody displayRowCheckbox={false} showRowHover> 
     {this.contacts.map((contact, index) => this._renderTableRow({ 
      hovered: index === this.state.hoveredRow, 
      ...contact })) 
     } 
     </TableBody> 
    </Table> 
} 

は、事前にありがとうございます。

答えて

4

あなたがそうのようなshouldComponentUpdateを実装する新しいコンポーネントにあなたの行をラップすることができます:あなたがしたくない場合は

this.contacts.map((contact, index) => <ContactRow key={contact.username} {...contact} hovered={index === this.state.hoveredRow} />) 

class ContactRow extends Component { 
    shouldComponentUpdate(nextProps) { 
     return this.props.hovered !== nextProps.hovered || ...; // check all props here 
    } 
    render() { 
     const { username, email, ...otherProps } = this.props; 
     return (
      <TableRow { ...otherProps } > 
       <TableRowColumn style={{ width: 24 }}> 
        {this.props.hovered ? checkBox : avatar} 
       </TableRowColumn> 
       <TableRowColumn>{this.props.username}</TableRowColumn> 
       <TableRowColumn>{this.props.email}</TableRowColumn> 
      </TableRow> 
     ); 
    } 
} 

次に、あなたはそうのようなあなたのContactListコンポーネントで使用することができますshouldComponentUpdateを手動で実装するには、ReactのPureRenderMixinを使用するか、のような役に立つヘルパーを提供するrecomposeのようなライブラリをチェックしてください。

EDIT

としては、上記のアプローチは、Tableコンポーネントのいくつかの機能とうまく再生されない、OPと@Denisによって指摘しました。具体的には、TableBodyは、その子どもの子供に対して何らかの操作を行います。より良いアプローチはそうのようなあなたのContactRowコンポーネントを定義するには、次のようになります。

class ContactRow extends Component { 
    shouldComponentUpdate(nextProps) { 
     // do your custom checks here 
     return true; 
    } 
    render() { 
     const { username, email, ...otherProps } = this.props; 
     return <TableRow { ...otherProps } />; 
    } 
} 

をしてから、この

<ContactRow { ...myProps }> 
    <TableRowColumn>...</TableRowColumn> 
</ContactRow> 

ようにそれを使用するためにしかし、私は機能の誰もが考えているときにのみ必要なTableRow再レンダリングした推測します恩恵を受けることができますので、おそらくPRが順番になるでしょう:)

+1

提案していただきありがとうございます。私たちはすでにこのアプローチを試みましたが、別の問題が発生しています:TableRowとTableは厳密に結びついており、 ReactコンポーネントでTableRowをラップすると、多くのことが壊れます(たとえば、tableRowのホバリングと選択はTableコンポーネントに正しく伝播されません)。 –

+0

@MatteoMazzarolo ok、私はそれを考慮に入れて私の答えを編集しました。この場合、TableBodyコンポーネントが継承しているすべての小道具をTableRowに渡す必要があります。 – VonD

+0

ありがとうございます。 TableBodyの小道具を渡しても正常に動作しないため、行ホバー上のリスト全体の再描画がトリガーされました。 残念ながら、これは時間に敏感な作業ですので、別のレイアウトに切り替えるので、次の日にさらに調査します。 私はあなたの答えがとにかく正しいと判断しています。なぜなら、よりよい解決策はないと思うからです。 私は間違っていると証明されることを願っています:) –

関連する問題