我正在 React.js 中开发一个 Web 应用程序,该应用程序将有一个显示项目的主面板和一个带有用于过滤项目的复选框的侧面板。我目前正在尝试将当前选定的复选框集传递回父页面 - 一旦它到达那里,我就可以担心将其推送到主显示。现在我希望只显示选中了多少个框,这样我就知道有些东西正在通过。
我查看了在React中使用复选框进行过滤,并得到了
useState
的粗略感觉,但它似乎对我不起作用 - 我相信我遇到的问题是我的数据库获取必须位于异步组件中,但是当我点击复选框时状态不会更新,我不知道如何解决这个问题。
这是我的代码:
'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
函数并使其异步,但这似乎没有任何区别。
我该如何进行这项工作?
fetchDesignKeywords 操作是异步的,直接在组件主体中调用它可能会导致不可预测的行为,因为 React 组件本质上是同步的。
而是使用useEffect 钩子来执行此操作,因为这是在 React 组件中处理异步操作的常见模式。
其次,在 React 组件中,如果一个值预计会随着时间的推移而改变或触发重新渲染,那么将其存储在组件的状态中是一个很好的做法。因此,最好使用useState 来存储从 fetchDesignKeywords 返回的数据。以下是更新后的代码供您参考。
请注意代码中的以下更改:
'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>
)
}