我试图在切换开关时显示/隐藏描述。我还想首先检查一下开关。当选中该开关时,应显示每个结果的描述。每个结果都有自己的描述。
我的代码没有做任何事情。相反,每个结果都会显示所有描述。切换开关不显示描述,但隐藏了它们。
// imports
const results = [...]
const upvoteSVG = '...';
const downvoteSVG = '...';
export default function SearchResults() {
const [page, setPage] = useState(0);
const [description, setDescription] = useState(Array.isArray(results) ? results.map(result => result.description) : []);
const List = () => {
return (
<>
{
results.slice(page * 10, page * 10 + 10).map((result) => {
return (
<div className="bg-gray-800 shadow-lg shadow-red-500 m-5">
<div className="flex flex-row gap-4 p-5">
<div className="flex flex-col w-1/2">
<div className="flex flex-row gap-4">
<p className="text-lg font-bold">{result.name}</p>
<p className="text-blue-500"><Link href={result.url}>Website</Link></p>
</div>
<p>{result.categories.slice(0, 3).join(", ")}</p>
</div>
<div className="flex flex-row flex-wrap w-1/2">
<p>{description}</p>
</div>
</div>
<div className="flex flex-row bottom-0 gap-4 bg-gray-900 justify-items-end justify-end pr-2">
<p>{result.upvotes}<button className="rounded-full bg-red-500 w-fit h-fit p-2 m-2"><Image src="upvote.svg" alt="upvote" width={20} height={20}/></button></p>
<p>{result.downvotes} <button className="rounded-full bg-red-500 w-fit h-fit p-2 m-2"><Image src="downvote.svg" alt="downvote" width={20} height={20}/></button></p>
</div>
</div>
)
})
}
</>
)
}
const prevPage = () => {...}
const nextPage = () => {...}
const showDescription = () => {
description ? setDescription([]) : setDescription(results.map(result => result.description));
}
const PaginationNumbers = () => {...}
const NOP = () => {...}
return (
<div className="flex flex-col justify-center items-center">
<div>
<Search/>
</div>
<div className="flex flex-row justify-center items-center">
<div className="w-1/2">
<List/>
</div>
<div className="w-1/2 m-2 p-2 flex flex-col justify-center items-center bg-gray-800">
<label className="inline-flex items-center cursor-pointer">
<input type="checkbox" value="" className="sr-only peer" id="toggle" onChange={showDescription}/>
<span className="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300 m-2">Show Description</span>
<div className="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-red-500 dark:peer-focus:ring-red-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-red-600" ></div>
</label>
</div>
</div>
<div className="flex flex-row justify-center items-center flex-wrap w-1/2">
<button onClick={prevPage} className="bg-gray-800 text-white m-2 p-2 hover:bg-white hover:text-black rounded-lg">Prev</button>
<PaginationNumbers/>
<button onClick={nextPage} className="bg-gray-800 text-white m-2 p-2 hover:bg-white hover:text-black rounded-lg">Next</button>
</div>
</div>
)
}
考虑转换:
const [description, setDescription] = useState(Array.isArray(results) ? results.map(result => result.description) : []);
对于布尔标志,例如:
const [showDescriptions, setShowDescription] = useState(false);
这简化了状态,并且依赖性更少。
然后,使用
showDescriptions
中的这个List
来有条件地显示描述:
{showDescriptions && (
<div className="flex flex-row flex-wrap w-1/2">
<p>{result.description}</p>
</div>
)}
更新
showDescription()
以匹配此新格式:
const showDescription = () => setShowDescription(value => !value);
const { useState } = React;
const Search = () => 'Search';
const Link = (...props) => <a {...props}/>;
const Image = (...props) => <img {...props}/>;
const results = [
{
name: 'Foo',
url: '',
categories: ['Foo', 'Bar'],
description: 'Foo description',
upvotes: 5,
downvotes: 5,
},
{
name: 'Bar',
url: '',
categories: ['Foo', 'Bar'],
description: 'Foo description',
upvotes: 5,
downvotes: 5,
},
{
name: 'Baz',
url: '',
categories: ['Foo', 'Bar'],
description: 'Foo description',
upvotes: 5,
downvotes: 5,
}
];
const upvoteSVG = '...';
const downvoteSVG = '...';
function SearchResults() {
const [page, setPage] = useState(0);
const [showDescriptions, setShowDescription] = useState(false);
const List = () => {
return (
<React.Fragment>
{results.slice(page * 10, page * 10 + 10).map((result) => {
return (
<div className="bg-gray-800 shadow-lg shadow-red-500 m-5">
<div className="flex flex-row gap-4 p-5">
<div className="flex flex-col w-1/2">
<div className="flex flex-row gap-4">
<p className="text-lg font-bold">{result.name}</p>
<p className="text-blue-500">
<Link href={result.url}>Website</Link>
</p>
</div>
<p>{result.categories.slice(0, 3).join(', ')}</p>
</div>
{showDescriptions && (
<div className="flex flex-row flex-wrap w-1/2">
<p>{result.description}</p>
</div>
)}
</div>
<div className="flex flex-row bottom-0 gap-4 bg-gray-900 justify-items-end justify-end pr-2">
<p>
{result.upvotes}
<button className="rounded-full bg-red-500 w-fit h-fit p-2 m-2">
<Image
src="upvote.svg"
alt="upvote"
width={20}
height={20}
/>
</button>
</p>
<p>
{result.downvotes}{' '}
<button className="rounded-full bg-red-500 w-fit h-fit p-2 m-2">
<Image
src="downvote.svg"
alt="downvote"
width={20}
height={20}
/>
</button>
</p>
</div>
</div>
);
})}
</React.Fragment>
);
};
const prevPage = () => {};
const nextPage = () => {};
const showDescription = () => setShowDescription(value => !value);
const PaginationNumbers = () => {};
const NOP = () => {};
return (
<div className="flex flex-col justify-center items-center">
<div>
<Search />
</div>
<div className="flex flex-row justify-center items-center">
<div className="w-1/2">
<List />
</div>
<div className="w-1/2 m-2 p-2 flex flex-col justify-center items-center bg-gray-800">
<label className="inline-flex items-center cursor-pointer">
<input
type="checkbox"
value=""
className="sr-only peer"
id="toggle"
onChange={showDescription}
/>
<span className="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300 m-2">
Show Description
</span>
<div className="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-red-500 dark:peer-focus:ring-red-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-red-600"></div>
</label>
</div>
</div>
<div className="flex flex-row justify-center items-center flex-wrap w-1/2">
<button
onClick={prevPage}
className="bg-gray-800 text-white m-2 p-2 hover:bg-white hover:text-black rounded-lg"
>
Prev
</button>
<PaginationNumbers />
<button
onClick={nextPage}
className="bg-gray-800 text-white m-2 p-2 hover:bg-white hover:text-black rounded-lg"
>
Next
</button>
</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('app')).render(<SearchResults />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.tailwindcss.com/3.4.3"></script>
<div id="app"></div>