2016-02-23 3 views
7

У меня есть массив объектов, хранящихся в redux. Я хочу, чтобы иметь возможность фильтровать этот массив на основе ввода пользователем. Должен ли я создать объект состояния, который получает массив через реквизит и модифицирует этот массив, или это плохая практика для смешивания состояния и реквизита? Если это нормально, смешайте два, следует ли установить состояние в компонентеWillReceiveProps?Лучший способ фильтрации таблицы в реакторе

+2

todomvc - это очень логичный подход для отслеживания состояния фильтрации. вот как это выглядит с помощью реакции/redux https://github.com/reactjs/redux/blob/master/examples/todomvc/components/MainSection.js – azium

+0

Я ищу больше для чего-то подобного https: // facebook. github.io/fixed-data-table/example-filter.html, за исключением того, что я получаю массив через реквизит, а не как его состояние. – Juliuszc

+2

Точно такой же принцип применяется. Помните, что ваши реквизиты - чужое государство. Вы сохраняете свой пользовательский ввод как состояние где-нибудь .. либо redux, либо в компоненте таблицы, а затем отфильтровывайте свой массив реквизитов против этого состояния фильтра. – azium

ответ

11

Состояние здания на основе реквизита может быть несколько сложным, что приемлемо, но вы должны рассмотреть все ваши варианты.

Простейший для реализации - это отфильтровать опоры в вашем методе render. Если у вас есть достаточно малые компоненты, которые не обновляют слишком много причин, и особенно, если количество элементов в списке является низким, это может быть предпочтительным способом:

class FilterList extends React.Component { 
    render() { 
    const { elements } = this.props; 
    const { filterStr } = this.state; 

    const filteredElements = elements 
     .filter(e => e.includes(filterStr)) 
     .map(e => <li>{ e }</li>) 

    return (
     <div> 
     <input 
      type="text" 
      value={ filterStr } 
      onChange={ e => this.setState({ filterStr: e.target.value }) } /> 
     <ul> 
      { filteredElements } 
     </ul> 
     </div> 
    ); 
    } 
} 

Следующая опция делать то, что вы описываете и выводите вычисленное состояние на основе состояния фильтра компонента и реквизита, переданного ему. Это хорошо, когда у вас сложный компонент, который получает много реквизитов и часто отображается. Здесь вы кешируете видимые элементы и только фильтруете список, когда его нужно фильтровать.

class FilterList extends React.Component { 
    constructor (props) { 
    this.state = { 
     viewableEls: props.elements 
    } 
    } 

    componentWillReceiveProps (nextProps) { 
    const { elements } = this.props; 
    const { filterStr } = this.state; 

    if (elements !== nextProps.elements) { 
     this.setState({ 
     viewableEls: this.getViewableEls(nextProps.elements, filterStr) 
     }) 
    } 
    } 

    getViewableEls (elements, filterStr) { 
    return elements.filter(el => el.includes(filterStr)) 
    } 

    handleFilterChange = e => { 
    const { elements } = this.props; 

    this.setState({ 
     filterStr: e.target.value, 
     viewableEls: this.getViewableEls(elements, filterStr) 
    }) 
    } 
    render() { 
    const { viewableEls } = this.state; 

    return (
     <div> 
     <input 
      type="text" 
      value={ filterStr } 
      onChange={ e => this.setState({ filterStr: e.target.value }) } /> 
     <ul> 
      { viewableEls.map(e => <li key={ e }>{ e }</li>) } 
     </ul> 
     </div> 
    ); 
    } 
} 

И, наконец, перевождь «путь», который требует, чтобы передать создателя действий и filterStr в качестве реквизита в компонент, вероятно, передали через connect где-то еще. Нижеприведенная реализация использует компонент без учета состояния, поскольку мы не сохраняем fitlerStr в состоянии компонента вообще.

const FilterTable = ({ elements, filterStr, changeFilterStr }) => { 
    return (
    <div> 
     <input 
     type="text" 
     value={ filterStr } 
     onChange={ e => changeFilterStr(e.target.value) } /> 
     <ul> 
     { 
      elements 
      .filter(e => e.includes(filterStr)) 
      .map(e => <li key={ e }>{ e }</li>) 
     } 
     </ul> 
    </div> 
) 
} 
+0

Спасибо, что поставили время, чтобы ответить на вопрос в глубину! – Juliuszc

+0

Первый и третий примеры неплохие. Однако я должен принять во внимание второй пример. Ваш 'this.state.viewableEls' получен полностью из реквизита и состояния, тогда как поля состояния должны действительно содержать уникальные фрагменты информации. Вы утверждаете, что это имеет преимущество кэширования, но я этого не вижу; поскольку рендер запускается только при обновлении реквизита/состояния. –

+0

В надуманном примере вы правы, нет никакой пользы для «кеширования», но если вы получаете другие реквизиты, которые вызывают 'render', но которые не должны влиять на значение' this.state.viewableEls', то есть. Если я не понимаю вас, конечно. Допустим, 90% повторных рендерингов вызвано сменой поддержки, с которой функция 'viewableEls' не является функцией (скажем, есть компонент чата в реальном времени, который является дочерним), а' elements' находится в диапазон в десятки тысяч элементов, будет возникать нетривиальное, но ненужное повторное вычисление каждый раз, когда приходит новое сообщение. Нет? –

Смежные вопросы