【问题标题】:Passing filter attributes to parent component将过滤器属性传递给父组件
【发布时间】:2018-03-17 14:19:54
【问题描述】:

我三个组件。

  1. 父母
  2. 列表项
  3. 过滤器组件

父级通过redux state获取它的数据:

家长

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 内部显示如下:

&lt;Grid&gt;{mappedEvents}&lt;/Grid&gt; 这给了我一个清单,

但我希望能够过滤它。所以我创建了一个过滤器组件,它也通过 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,还是应该过滤器组件将回调回调给父级,并且父级呈现过滤后的列表?

【问题讨论】:

    标签: javascript reactjs filter redux


    【解决方案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 根据您的过滤器状态过滤事件。

    您可以使用 reselect 之类的东西来缓存过滤后的列表,但是对于一个小列表,您应该不会看到单个过滤器函数的任何性能问题。

    // 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

    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')
    );
    <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>

    【讨论】:

    • 感谢您的回复。首先我想说当我看到你的个人资料照片时我开始笑了(不知道为什么)。我猜减速器应该做过滤?然后我会通过mapStateToProps将我的过滤器返回给父组件?抱歉,我很难想象这一点,我真的被卡住了。
    • 这是一张有趣的图片 :) -- 我在帖子中添加了更多信息,如果您有其他问题,请告诉我
    • 所以每次我想过滤其他内容时,我都需要在我的initialState? 中添加该属性?我怎样才能将它们从false 更改为truefilter component 是否应该通过 redux 存储访问这些值,并且在选择复选框时,值应该从 false 变为 true?奥斯汀的一切仍然模糊不清。我不怪你,我很抱歉我缺乏知识。
    • 添加了一个小演示,可能会有所帮助,有些事情是不同的,因为没有 redux,但它应该提供一个良好的起点。
    • 非常感谢您的 sn-p。我想知道有没有什么方法可以和你讨论这个问题?由于您提供的 sn-p,我会接受您的回答。我还没有解决我的问题,这很糟糕。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 2021-07-12
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多