使用复选框从React.js/Next.js中的数据库中过滤数据

ni65a41a  于 12个月前  发布在  React
关注(0)|答案(2)|浏览(158)

我正在用React.js开发一个web应用,它将有一个显示项目的主面板,以及一个带有复选框的侧面板来过滤项目。我目前正在尝试将当前选中的复选框集传递回父页面-一旦它在那里,我就可以担心将其推送到主显示屏。现在我希望只显示有多少复选框被选中,所以我知道有什么东西要进来
我看了看Filtering with checkboxes in React,对useState有了一个粗略的了解,但它似乎对我不起作用-我相信我遇到的问题是我的DB获取必须在一个Apache组件中,但当我点击复选框时,状态不会更新,我不知道如何解决这个问题。
下面是我的代码:

'use client'

import { fetchDesignKeywords } from '@/app/lib/data'; /* returns an Array of 2-element arrays */
import { useState } from 'react';

function KeywordFilterControl(props) {
    return(
        <ul className="w-[180px] truncate">
            {props.dks.map(keyword => {
                return(
                    <div key={keyword[0]}>
                        <label className="form-check-label" key={keyword[0]}>
                            <input className="form-check-input mr-2" id={keyword[0]} type="checkbox"
                                onChange={e => props.updateFilters(e.target.checked, keyword[0])}></input>
                            {keyword[0]} ({keyword[1]})
                        </label>
                    </div>
                );
            })}
        </ul>
    );
}

export default async function Page() {
    let [categoryFilters, setCategoryFilters] = useState(new Set());

    const dks = await fetchDesignKeywords()
    function updateFilters(checked, categoryFilter) {
        console.log(categoryFilter)
        if (checked)
          setCategoryFilters((prev) => new Set(prev).add(categoryFilter));
        if (!checked)
          setCategoryFilters((prev) => {
            const next = new Set(prev);
            next.delete(categoryFilter);
            return next;
          });
      }
    return (
        <div>
            
            <div className="flex flex-row">
                <KeywordFilterControl 
                    updateFilters={updateFilters}
                    dks={dks}/>
                <p>Selected: {categoryFilters.size}</p>
            </div>
        </div>
    )
}

字符串
我希望console.log(categoryFilter)在我单击复选框时记录一些内容,<p>Selected: {categoryFilters.size}</p>更新计数。这两种情况都没有发生-控制台日志中没有显示任何内容,计数仍然为0。
我试过将const dks = await fetchDesignKeywords()移到KeywordFilterControl函数中,并将其改为xmlc,但这似乎没有任何区别。
我该怎么做?
编辑:在map函数中添加一个console.log(keyword);语句将把完整的关键字列表打印到我的控制台。

kpbpu008

kpbpu0081#

fetchDesignKeywords操作是异步的,直接在组件体中调用它可能会导致不可预测的行为,因为React组件本质上是同步的。

相反,使用useEffecthook来执行此操作,因为这是处理React组件中异步操作的常见模式。
其次,在React组件中,如果一个值预期会随着时间的推移而改变或者触发重新渲染,那么将其存储在组件的状态中是一个很好的做法。因此,最好使用useState来存储从fetchDesignKeywords返回的数据。下面是更新后的代码供您参考。
请注意代码中的以下更改:

*页面组件不再是可扩展组件
*已添加新状态
*useEffect用于对对象进行操作

'use client'

import { fetchDesignKeywords } from '@/app/lib/data';
import { useState, useEffect } from 'react';

function KeywordFilterControl(props) {
    return (
        <ul className="w-[180px] truncate">
            {props.dks.map(keyword => (
                <div key={keyword[0]}>
                    <label className="form-check-label" key={keyword[0]}>
                        <input
                            className="form-check-input mr-2"
                            id={keyword[0]}
                            type="checkbox"
                            onChange={e => props.updateFilters(e.target.checked, keyword[0])}
                        ></input>
                        {keyword[0]} ({keyword[1]})
                    </label>
                </div>
            ))}
        </ul>
    );
}

export default function Page() {
    const [categoryFilters, setCategoryFilters] = useState(new Set());

    // declaring a new State for storing result of fetchDesignKeywords()
    const [dks, setDks] = useState([]);

    // using useEffect for performing async operation call

    useEffect(() => {
        const fetchData = async () => {
            try {
                const data = await fetchDesignKeywords();
                setDks(data);
            } catch (error) {
                console.error('Error fetching data:', error);
            }
        };

        fetchData();
    }, []); 

    function updateFilters(checked, categoryFilter) {
        console.log(categoryFilter)
        if (checked)
            setCategoryFilters((prev) => new Set(prev).add(categoryFilter));
        if (!checked)
            setCategoryFilters((prev) => {
                const next = new Set(prev);
                next.delete(categoryFilter);
                return next;
            });
    }

    return (
        <div>
            <div className="flex flex-row">
                <KeywordFilterControl
                    updateFilters={updateFilters}
                    dks={dks} />
                <p>Selected: {categoryFilters.size}</p>
            </div>
        </div>
    )
}

字符串

kkih6yb8

kkih6yb82#

我最后做的是:

  • KeywordFilterControl和处理函数移到一个单独的文件中,这样我就可以在那里保留“use client”钩子。
  • 使用useSearchParams在过滤器控制和searchParamsPage把我选择的关键字.
export default function KeywordFilterControl(props) {
    const searchParams = useSearchParams();
    const pathname = usePathname();
    const { replace } = useRouter();

    function handleCheck(checked, term) {
        const params = new URLSearchParams(searchParams)
        if(checked && !params.has('keywords')) {
            params.set('keywords',','.concat(term,','))
        } else if (checked) {
            params.set('keywords',params.get('keywords')?.concat(',',term,','));
        } else {
            params.set('keywords',params.get('keywords')?.replace(','.concat(term,','),''));
        }
        replace(`${pathname}?${params.toString()}`);

      }

    return(
        <ul className="w-[180px] truncate">
            {props.dks.map(keyword => {
                return(
                    <div key={keyword[0]}>
                        <label className="form-check-label" key={keyword[0]}>
                            <input 
                                className="form-check-input mr-2" 
                                id={keyword[0]} 
                                type="checkbox"
                                onChange={e => handleCheck(e.target.checked, keyword[0])}
                                defaultChecked={searchParams.get('keywords')?.includes(keyword[0])}
                                ></input>
                            {keyword[0]} ({keyword[1]})
                        </label>
                    </div>
                );
            })}
        </ul>
    );
}

字符串

相关问题