将过滤器属性传递给父组件

时间:2017-10-05 20:44:15

标签: javascript reactjs filter redux

我有三个组成部分。

  1. 列表项
  2. 过滤器组件
  3. 父母通过redux状态获取数据:

    const mappedEvents =
      events.length === 0 ? (
        <p style={{ textAlign: 'center' }}>Det finns inte några händelser</p>
      ) : (
        events.reverse().map((event, i) => {
          var driver = event.driver ? keyedDrivers[event.driver] : false
          var carrier = driver ? keyedCarriers[driver.carrier] : false
          var customer = event.customer ? keyedCustomers[event.customer] : false
    
          return (
            <div>
              <EventItem // This is a list item
                key={i}
                event={event}
                customer={customer}
                carrier={carrier}
                driver={driver}
                lock={keyedLocks[event.unit] || { address: {} }}
              />
            </div>
          )
        })
      )
    

    然后在return内部,我将其显示为:

    <Grid>{mappedEvents}</Grid> 这给了我一个清单,

    但我希望能够过滤它。所以我创建了一个过滤器组件,它也可以通过redux状态获取它的数据。

    过滤器组件

      constructor(props) {
        super(props)
        this.state = {
          filteredEvents: ''
        }
      }
    
      toggle(event) {
        this.setState({ filteredEvents: event.target.value })
      }
      ...
    
    const organizationList = carriers
      .filter(
        carrier =>
          !this.state.filteredEvents ||
          carrier.organization.indexOf(this.state.filteredEvents) >= 0
      )
      .map(carrier => (
        <div>
          <input
            type="checkbox"
            value={carrier.organization}
            onChange={this.toggle.bind(this)}
          />
          <MenuItem eventKey={carrier.id} key={carrier.id}>
            {carrier.organization}
          </MenuItem>
        </div>
      ))
    

    这会呈现用户可以检查的内容列表:

    然而,当我点击其中一个复选框时,它开始过滤复选框数组:

    所以我想知道如何传递过滤器组件,以便我可以开始过滤EventItem数组。我是否应该开始制作一个进行过滤的reducer,或者过滤器组件是否应该将回调调用回父级,而parent会呈现过滤后的列表吗?

1 个答案:

答案 0 :(得分:1)

基本上,您希望将过滤器状态保留在redux存储中。您的过滤器应该调度更新状态的操作,然后在渲染列表时,您将在那里过滤它。

events.filter((event) => {
  // filter based on redux state
}).reverse().map((event, i) => {

-

toggle(event) {
  // this.setState({ filteredEvents: event.target.value })
  // dispatch an action that updates the redux state filters here
}

多一点信息

我可能会将过滤器存储为布尔值。 Reducer初始状态看起来像这样(或者你可以为事件/过滤器设置单独的reducer):

events: [],
filters: {
  qlocx: false,
  best: false,
  bring: false // etc..
}

更新过滤器操作将设置与复选框对应的过滤器布尔值。

在您的mapStateToProps中,您将同时拥有eventsfilters

然后在渲染功能中,您可以使用.filter根据过滤器状态过滤事件。

您可以使用类似重新选择的内容来缓存已过滤的列表,但如果只有一个小列表,则您不应该从单个过滤器功能中看到任何性能问题。

// inside the render function, filter the array based on filters set
// just a simple render function example for demonstration
render() {
  return (
    <div>
      {events
        .filter((event) => {
          // filter based on redux state
          if (event.qlocx && filters.qlocx) {
            return true;
          }
          // etc..

          // filter any that don't match (might want to return true if no filters are set)
          return false;
        })
        .reverse()
        .map((event, i) => {

<强>演示

这是一个小型演示,但没有redux。它使用setState作为已调度操作的替代,并将状态向下传递为道具,而不是使用mapStateToProps

&#13;
&#13;
class Filters extends React.Component {
  onUpdateFilter = (event) => {
    // event.target is the input that you changed, so you can get the name and checked properties
    this.props.updateFilters(event.target.name, event.target.checked);
  }
  
  render() {
    const {
      filters
    } = this.props;

    return (
      <div>
        <input type="checkbox" name="one" onChange={this.onUpdateFilter} value={filters.one} />
        <input type="checkbox" name="two" onChange={this.onUpdateFilter} value={filters.two} />
        <input type="checkbox" name="three" onChange={this.onUpdateFilter} value={filters.three} />
      </div>
    );
  }
}

class List extends React.Component {
  // this would be your reducer's `initialState`
  state = {
    filters: {}
  };
  
  // this code would be in your reducer, and you'd just dispatch an action here
  updateFilters = (name, value) => {
    this.setState({
      filters: {
        // this just makes a copy of state.filters and sets state.filters[name] = value
        ...this.state.filters,
        [name]: value
      }
    });
  }

  render() {
    // both filters and items would come from mapStateToProps
    const {filters} = this.state;
    const {items} = this.props;

    return (
      <div>
        <pre>filters = {JSON.stringify(filters)}</pre>
        <Filters
          filters={filters}
          updateFilters={this.updateFilters}
        />
        <ul>
          {this.props.items
            .filter((item) => {
              if (filters.one && !item.one) {
                return false;
              }
              if (filters.two && !item.two) {
                return false;
              }
              if (filters.three && !item.three) {
                return false;
              }
              
              return true;
            })
            .map((item) => (
              <li key={item.name}>{item.name}</li>
            ))
          }
        </ul>
      </div>
    );
  }
}

// this list would come from your reducer via mapStateToProps
const listItems = [
  {name: 'Item 1', one: true},
  {name: 'Another item 1', one: true},
  {name: 'Item 2', two: true},
  {name: 'Item 2,1', one: true, two: true},
  {name: 'Item 2,3', two: true, three: true},
  {name: 'Item 3', three: true}
];

ReactDOM.render(
  <List items={listItems} />,
  document.getElementById('app')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
&#13;
&#13;
&#13;