处理 React 应用程序中的复选框

Pav*_*l L 5 javascript reactjs

在我的 React 应用程序中,我试图在单击复选框时捕获一些事件以进行一些状态过滤,并且只显示需要的项目。 event来自带有一些name. 有 3 个复选框,所以我需要知道name点击了哪一个。

他们中的一些

<input 
  type="checkbox" 
  name="name1"
  onClick={filterHandler} 
/>Something</div>
Run Code Online (Sandbox Code Playgroud)

状态就像

state = {
  items = [
   { 
    name: "name1",
    useful: true
   },{
    name: "name2",
    useful: false
   }],

   filteredItems: []  
} 
Run Code Online (Sandbox Code Playgroud)

这是处理程序

 filterHandler = (evt) => {

    let checked = evt.target.checked;
    let name = evt.target.name;

    let filteredItems = this.state.items.filter(item => {
     return item[name] === checked; // filtered [{...},{...}...]
    });

    // when filtered - push to state and show all from here in <ItemsList />
    this.setState({ filteredItems })
 }
Run Code Online (Sandbox Code Playgroud)

用于“显示”的 ItemsList 组件如下所示:

<ItemsList 
  items={this.state.filteredItems.length === 0 ? this.state.items : this.state.filteredItems}
          /> 
Run Code Online (Sandbox Code Playgroud)

当复选框是一个且唯一时 - 它工作正常。但是我有三个这样的盒子——出现了并发症:

1)当检查下一个框时,我使用原始未过滤的项目数组 - 所以为此我需要已经过滤的数组。2)我不能使用我filteredItems以前过滤过的数组,因为当取消选中该数组为空的框时。拥有第三个“临时”数组似乎有点奇怪。

我试过这种方式,也很相似

this.setState({
  filteredItems: this.state.items.filter(item => {
    if (item[name] === checked) {
      console.log('catch');
      return Object.assign({}, item)
    } else {
      console.log('no hits') 
    }
 })
Run Code Online (Sandbox Code Playgroud)

这几乎是好的,但是当取消选中filteredItems时填充相反的值((

我觉得有更好的方法,请提出建议。

Mel*_*igy 6

您可以通过存储过滤器的选中状态来实现。

例如,您的状态可能类似于:

state = {
    items: [
    {
        name: "name1",
        useful: true
    },
    {
        name: "name2",
        useful: false
    }
    ],
    filters: { 'name1': false, 'name2': false}, // key value pair name:checked
    filteredItems: []
};
Run Code Online (Sandbox Code Playgroud)

然后您的点击/更改处理程序将更新过滤列表和实际过滤器状态(选中的内容)。

这是一个例子:(
更新:根据评论中的要求进行了大量评论)

  // Using syntax: someFunc = (params) => { ... }
  // To avoid having to bind(this) in constructor
  onChange = evt => {
    // const is like var and let but doesn't change
    // We need to capture anything dependent on
    //  evt.target in synchronous code, and
    //  and setState below is asynchronous
    const name = evt.target.name;
    const checked = evt.target.checked;

    // Passing function instead of object to setState
    // This is the recommended way if
    //    new state depends on existing state
    this.setState(prevState => {
      // We create a new object for filters
      const filters = {
        //  We add all existing filters
        //  This adds them with their existing values
        ...prevState.filters,
        // This is like:
        //    filters[name] = checked
        // which just overrides the value of
        //    the prop that has the name of checkbox
        [name]: checked
      };

      // Object.keys() will return ["name1", "name2"]
      // But make sure that "filters" in
      //    our initial state has all values
      const activeFilterNames = Object.keys(filters).filter(
        // We then filter this list to only the ones that
        //    have their value set to true
        //    (meaning: checked)
        // We set this in the `const filter =` part above
        filterName => filters[filterName]
      );

      // We get the full list of items
      // (Make sure it's set in initial state)
      // Then we filter it to match only checked
      const filteredItems = prevState.items.filter(item =>
        // For each item, we loop over
        //     all checked filters
        // some() means: return true if any of the
        //    array elements in `activeFilterNames`
        //    matches the condition
        activeFilterNames.some(
          // The condition is simply the filter name is
          //    the same as the item name
          activeFilterName => activeFilterName === item.name
        )
      );

      // The object returned from setState function
      //    is what we want to change in the state
      return {
        // this is the same as
        // { filter: filters,
        //    filteredItems: filteredItems }
        // Just taking advantage of how const names
        //    are the same as prop names
        filters,
        filteredItems
      };
    });
  };
Run Code Online (Sandbox Code Playgroud)

我在这里使用 JS / Babel 的最新功能,但希望代码很清楚。我也必须evt.target在进入之前使用setState()

这是一个完整的组件示例:

import * as React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  state = {
    items: [
      {
        name: "name1",
        useful: true
      },
      {
        name: "name2",
        useful: false
      }
    ],
    filters: { name1: false, name2: false },
    filteredItems: []
  };

  // Using syntax: someFunc = (params) => { ... }
  // To avoid having to bind(this) in constructor
  onChange = evt => {
    // const is like var and let but doesn't change
    // We need to capture anything dependent on
    //  evt.target in synchronous code, and
    //  and setState below is asynchronous
    const name = evt.target.name;
    const checked = evt.target.checked;

    // Passing function instead of object to setState
    // This is the recommended way if
    //    new state depends on existing state
    this.setState(prevState => {
      // We create a new object for filters
      const filters = {
        //  We add all existing filters
        //  This adds them with their existing values
        ...prevState.filters,
        // This is like:
        //    filters[name] = checked
        // which just overrides the value of
        //    the prop that has the name of checkbox
        [name]: checked
      };

      // Object.keys() will return ["name1", "name2"]
      // But make sure that "filters" in
      //    our initial state has all values
      const activeFilterNames = Object.keys(filters).filter(
        // We then filter this list to only the ones that
        //    have their value set to true
        //    (meaning: checked)
        // We set this in the `const filter =` part above
        filterName => filters[filterName]
      );

      // We get the full list of items
      // (Make sure it's set in initial state)
      // Then we filter it to match only checked
      const filteredItems = prevState.items.filter(item =>
        // For each item, we loop over
        //     all checked filters
        // some() means: return true if any of the
        //    array elements in `activeFilterNames`
        //    matches the condition
        activeFilterNames.some(
          // The condition is simply the filter name is
          //    the same as the item name
          activeFilterName => activeFilterName === item.name
        )
      );

      // The object returned from setState function
      //    is what we want to change in the state
      return {
        // this is the same as
        // { filter: filters,
        //    filteredItems: filteredItems }
        // Just taking advantage of how const names
        //    are the same as prop names
        filters,
        filteredItems
      };
    });
  };

  renderCheckboxes() {
    return Object.keys(this.state.filters).map((name, index) => {
      return (
        <label key={index}>
          <input
            onChange={this.onChange}
            type="checkbox"
            checked={this.state.filters[name]}
            name={name}
          />
          {name}
        </label>
      );
    });
  }

  render() {
    const items = this.state.filteredItems.length
      ? this.state.filteredItems
      : this.state.items;
    return (
      <div>
        <div>{this.renderCheckboxes()}</div>
        <ul>
          {items.map(item => (
            <li key={item.name}>
              {item.name}
              {item.useful && " (useful)"}
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)

您可以从这里实时试用:https :
//codesandbox.io/embed/6z8754nq1n

您当然可以根据需要创建不同的变体。例如,您可以选择将过滤移动到渲染函数而不是更改事件,或者存储您存储所选过滤器的方式等,或者直接使用它。什么最适合你:)