【问题标题】:React - Checkbox select allReact - 复选框全选
【发布时间】:2018-09-17 15:33:57
【问题描述】:

我有一个项目列表,每个项目都有自己的复选框,我决定尝试添加一个“全选”复选框,以便用户更轻松地一次选择所有项目。

不幸的是,我发现很难以某种“反应”的方式来解决逻辑。

我找到了一个关于我希望渲染结果如何工作的 JSBIN - https://jsbin.com/jetalaxaha/edit?html,js,output 注意:这与我希望的设置方式不同。

我当前的代码在这里:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Items extends Component {
    state = {
        categories: [
            {
                id: 1,
                name: "category 1",
                items: [
                    { name: "item 1", id: Math.floor(Math.random() * 99999) },
                    { name: "item 2", id: Math.floor(Math.random() * 99999) }
                ]
            },
            {
                id: 2,
                name: "category 2",
                items: [
                    { name: "item 3", id: Math.floor(Math.random() * 99999) },
                    { name: "item 4", id: Math.floor(Math.random() * 99999) }
                ]
            },
            {
                id: 3,
                name: "category 3",
                items: [
                    { name: "item 5", id: Math.floor(Math.random() * 99999) }
                ]
            }
        ],
        checkedListAll: [],
        ItemsChecked: false
    };
    selectedItems(e) {
        const { value, checked } = e.target;
        let { checkedListAll } = this.state;

        if (checked) {
            checkedListAll = [...checkedListAll, value];
        } else {
            checkedListAll = checkedListAll.filter(el => el !== value);
            if (this.state.ItemsChecked) {
                this.setState({
                    ItemsChecked: !this.state.ItemsChecked
                });
            }
        }
        this.setState({ checkedListAll });
    }
    selectItem(e) {
        const { checked } = e.target;
        const { categories } = this.state;
        const collection = [];

        if (checked) {
            this.setState(
                {
                    checkedListAll: []
                },
                () => {
                    for (const cat of categories) {
                        for (const item of cat.items) {
                            collection.push(item.id);
                        }
                    }

                    this.setState({
                        checkedListAll: collection
                    });
                }
            );
        } else {
            this.setState({
                checkedListAll: []
            });
        }
        this.setState({
            ItemsChecked: !this.state.ItemsChecked
        });
    }
    render() {
        const { categories, checkedListAll, ItemsChecked } = this.state;

        return (
            <div>
                <header>
                    <label>
                        <input
                            type="checkbox"
                            checked={ItemsChecked}
                            onClick={this.selectItem.bind(this)}
                        />Select all
                    </label>
                </header>
                {categories.map(cat => {
                    return (
                        <ItemCategory
                            {...cat}
                            key={cat.id}
                            click={this.openModal}
                            selectedItems={this.selectedItems.bind(this)}
                            ItemsChecked={ItemsChecked}
                        />
                    );
                })}
                {
                    <pre>
                        All Selected: {JSON.stringify(ItemsChecked, null, 2)}
                    </pre>
                }
                {
                    <pre>
                        Selected List: {JSON.stringify(checkedListAll, null, 2)}
                    </pre>
                }
            </div>
        );
    }
}

class ItemCategory extends Component {
    render() {
        const { items, name, selectedItems, ItemsChecked } = this.props;

        const getItems = items.map(item => {
            return item;
        });

        return (
            <div>
                <div>-{name}</div>
                <ul>
                    {getItems.map(item => {
                        return (
                            <li key={item.id}>
                                <Checkbox
                                    item={item}
                                    selectedItems={selectedItems}
                                    ItemsChecked={ItemsChecked}
                                />
                            </li>
                        );
                    })}
                </ul>
            </div>
        );
    }
}

class Checkbox extends Component {
    state = {
        isChecked: false
    };
    componentDidUpdate(prevProps) {
        if (prevProps.ItemsChecked !== this.props.ItemsChecked) {
            this.setState({
                isChecked: !this.state.isChecked
            });
        }
    }
    handleClick(e) {
        e.persist();
        if (this.props.ItemsChecked) {
            console.log(true);
        }
        this.setState(
            {
                isChecked: !this.state.isChecked
            },
            () => {
                this.props.selectedItems(e);
            }
        );
    }
    render() {
        const { item } = this.props;
        const { isChecked } = this.state;

        console.log(this.props.ItemsChecked);
        return (
            <label>
                <input
                    type="checkbox"
                    value={item.id}
                    checked={isChecked}
                    onClick={this.handleClick.bind(this)}
                />
                {item.name}
            </label>
        );
    }
}

function App() {
    return <Items />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

也可作为代码框使用 - https://codesandbox.io/s/r44yn2rwm4

当前未解决的问题/要添加的额外功能:

  • 单击“全选”复选框,然后取消选中其中一个项目复选框会取消选择其余的复选框。
  • 单独选择所有项目应勾选“全选”复选框
  • 修复“选定列表”ID 集合

对此的任何帮助将不胜感激,已经为此工作了一段时间并用尽了所有途径!

【问题讨论】:

  • 你反转检查状态。为这个用例做一个隐式 selectAll / unselectAll 并且不要ItemsChecked: !this.state.ItemsChecked - 去true/false。您当前的实现是“切换” - 不检查。

标签: javascript reactjs


【解决方案1】:

Working codesandbox

我已经对代码框进行了一些更改,并对其进行了更正。最好与您的比较以查看所有更改,但总结一下:

  • Items 组件中管理复选框的选中状态,而不是处理其自身状态的复选框。将状态作为道具传递给它,并将其传递给更改事件处理程序。

  • 当单击全选时,您希望将 checkedListAll 数组中的所有项目 ID 放入 state 而不是切换它们。

这是处理复选框更改事件的关键更改。选中后,将使用现有项目和新项目创建一个新数组。未选中时,.filter() 创建一个新数组,过滤掉要删除的项目。

handleCheckboxClick(e) {
  const { value, checked } = e.target;

  if (checked) {
    this.setState(prevState => ({
      checkedListAll: [...prevState.checkedListAll, value * 1]
    }));
  } else {
    this.setState(prevState => ({
      checkedListAll: prevState.checkedListAll.filter(item => item != value)
    }));
  }
}

【讨论】:

  • 太棒了 :) 正是我需要的那种功能。我经历了你的改变,它帮助我更多地理解了我哪里出错了。非常感谢:)
【解决方案2】:

我已修改 @MrCode fiddle 以进行更多更改,因为缺少功能检查/取消选中基于单个项目选择所有复选框。因此,如果选中/取消选中单个项目,它也应该重置“全选”状态。

if (checked) {
    const collection = this.getAllItems();
    this.setState(prevState => ({
        checkedListAll: [...prevState.checkedListAll, value * 1],
        ItemsChecked: collection.length === prevState.checkedListAll.length + 1
    }));
} else {
    this.setState(prevState => ({
        checkedListAll: prevState.checkedListAll.filter(item => item != value),
        ItemsChecked: false
    }));
}

Working Codesandbox

【讨论】:

  • 很棒的东西,我自己也在尝试,因为它是唯一出色的功能,但您的代码工作得更好,更精简。谢谢:)
【解决方案3】:

我会检查您的属性类型。根据您链接的 CodeSandbox,请注意当您单击“全选”然后单独选中复选框时,“全选”中的数字和单个复选框中的字符串。

【讨论】:

    猜你喜欢
    • 2016-02-20
    • 2011-04-02
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多