如何使用复选框过滤数据,而不使用Redux

时间:2019-01-03 00:41:41

标签: javascript reactjs redux react-redux

我正在使用React来显示我想按类别过滤的书名。单击类别名称旁边的复选框后,我希望对标题进行过滤。我没有使用提交按钮。

我对React还是有些陌生,并且阅读了有关“提升状态”的文档,但是我无法使其正常工作。我尚未阅读Hooks或Context API文档。也许这就是解决方案,但看来我正在做的事情还不够复杂……也许不是吗?

class Checkbox extends Component {
    state = {
        checked: false
    }

    handleClick = (e) => {
        this.setState(() => ({ checked: !this.state.checked }))
    }

    render() {
        const name = this.props.name;
        return (
            <label className="form__group">
                <input type="checkbox" checked={this.state.checked} onChange={this.handleClick} className="form__input" />
                <span className="form__faux-input"></span>
                <span className="form__label">{name}</span>
            </label>
        )
    }
}

function Sidebar({ categories }) {
    return (
        <div className="sidebar">
            <div className="controls">
                <div className="filter">
                    <h2 className="filter__heading">Filter By Category</h2>
                    <form className="filter-form">
                        {!categories
                            ? <Spinner />
                            : categories.map((item) => (
                                <Checkbox key={item} name={item} />
                            ))
                        }
                        <div className="form__group">
                            <button className="btn btn--rectangle btn--green">
                                <span className="btn-wrapper">Reset</span>
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    );
}

class App extends Component {
    state = {
        books: null,
        categories: null
    }

    async componentDidMount() {
        const { books, categories } = await getBooks();

        this.setState(() => ({
            books: books,
            categories: categories
        }));
    }

    render() {
        const { books } = this.state;
        const { categories } = this.state;
        return (
            <div className="App">
                <Header />
                <main className="main">
                    <div className="uiContainer">
                        <Sidebar
                            categories={categories}
                        />
                        {!books
                            ? <Spinner />
                            : <Card books={books} />
                        }
                    </div>
                </main>
            </div>
        );
    }
}

2 个答案:

答案 0 :(得分:0)

我不是100%理解这个问题,但是如果您想像这样的部分

[x]  cats
[x]  dogs
[ ]  rabbits // dont show rabbits

如果您不了解“提升状态”部分,则可以将选择和结果部分保留在一个react元素中

状态应包含这样的对象数组:

[{
    allow: true,
    title: 'cat'
},
{allow: false, title: 'rabbit'}]

要更新列表,请使用以下内容:

this.state.map(({title, allow}) => (
    <div>
        <TickBox onClick={() => this.toggleAnimal(title)} value={allow}/>
        <p>{animalName}</p>
    </div>
)

toggleAnimal函数应使用标题查找动物,并更新状态

然后您可以过滤掉所有不允许的动物

this.state
   .filter(animal => animal.allowed)
   .map(a => <p>{a.title}</p>)

提升状态

此时,您有1个组件,渲染函数如下所示:

<h1>Please select the animals</h1>
{
    animals.map(_ => <div><tickbox onClick={() => this.handleToggle(title)} /><title></div>)
}
<h1>Here are the filtered animals</h1>
{
    animals.filter(a => a.allow).map(animal => animal.title).map(/* to JSX */)
}

如果根组件看起来像这样,则会更漂亮且响应更快:

render () {
    <SelectAnimals toggle={handleToggle} animals={this.state} />
    <ShowFilteredAnimals animals={this.state} />
}
handleToggle (title) {
    this.setState(...)
}

可以看到,SelectAnimals通过调用props.toggle(以标题为参数)来获取一个函数作为参数,它可以与其父级进行通信

所以SelectAnimals看起来像这样:

props.animals.map(animal => (
 <div>
   <TickBox onClick=(() => {props.toggle(animal.title)}) /> // HERE
   <p>{animal.title}</p>
 </div>
))

因此,当勾号框触发click事件时,它将调用箭头功能。用标题调用props.toggle函数 在SelectAnimals的父级中,父元素将处理程序函数绑定到SelectAnimals.toggle,如下所示:     

handleToggle (title) { // the child element called this function, it just got copied
}

PS:我在代码中进行了一些重命名,handleToggle函数可以与toggleAnimals相同

答案 1 :(得分:0)

假设列表呈现的位置是App,则父组件Card必须能够告诉Card所选类别是什么。

为此,您可以:

1)在<App>内创建一个回调函数:

_setCurrentCategory(selection) { 
  this.setState({currentCategory: selection}) 
}

2)将其作为道具传递给<Checkbox />,并在onChange中使用它:

  class Checkbox extends Component {
    render() {
        const {name, setCurrentCategoryCallback } = this.props
        return (
            <label className="form__group">
                <input
                  type="checkbox"
                  onChange={() => setCurrentCategoryCallback(name)}
                  className="form__input"
                />
                <span className="form__faux-input"></span>
                <span className="form__label">{name}</span>
            </label>
        )
    }
  }

..这将更改父级中的状态,以便您可以

2)然后将状态从<App />传递到<Card />

<Card 
  currentCategory={this.state.currentCategory} 
  books={books}
/> 

^^假定这是过滤列表将呈现的位置。在Card组件内部,您可以过滤/排序然后根据需要呈现列表,因为它现在同时具有书籍列表和当前选定的类别。

这是非常宽松的代码,但希望您能理解!

此外,在解构时,您不需要这样做:

const { books } = this.state;
const { categories } = this.state; 

您可以改为:const { books, categories} = this.state,因为它们都来自状态:)