英文:
Need to refactor to use both GoChevronDown and GoChevronLeft
问题
我有一个需要重构的DropDown组件,根据用户点击选择标签,我需要使用GoChevronDown
和GoChevronLeft
进行重构。我已经尝试了自己的方法,但始终只得到一个空白屏幕:
import { useState } from "react";
import { GoChevronDown, GoChevronLeft } from "react-icons/go";
function Dropdown({ options, value, onChange }) {
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
setIsOpen(!isOpen);
};
const handleOptionClick = (option) => {
// 关闭下拉菜单
setIsOpen(false);
// 用户点击了哪个选项?
onChange(option);
};
const renderedOptions = options.map((option) => {
return (
<div
className='hover:g-sky-100 rounded cursor-pointer p-1'
onClick={() => handleOptionClick(option)}
key={option.value}
>
{option.label}
</div>
);
});
return (
<div className='w-48 relative'>
<div
className='flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full'
onClick={handleClick}
>
{value?.label || "Select..."} {isOpen ? <GoChevronLeft className='text-3xl' /> : <GoChevronDown className='text-3xl' />}
</div>
{isOpen && (
<div className='absolute top-full border rounded p-3 shadow bg-white w-full'>
{renderedOptions}
</div>
)}
</div>
);
}
export default Dropdown;
我尝试在映射函数中添加了一个index
,然后将该索引与isOpen
进行比较。
我还创建了一个图标变量,其中我放置了一些包含两个chevron图标的span标签。
我想必须将第二个return语句中的某些元素放在映射函数内部,但无论如何我做都只会得到一个空白屏幕。
我在这里有一个我尝试的最小可重现示例:
但你会看到它看起来不正确。
应该有一个带有右侧图标的Select...,当你点击它时,会下拉一些项目,确切地说是"red"、"green"、"blue"。
英文:
So I have a DropDown component that I need to refactor to use GoChevronDown
and GoChevronLeft
depending upon the user clicking the Select label, I have tried this on my own and I continue to just get a blank screen:
import { useState } from "react";
import { GoChevronDown } from "react-icons/go";
function Dropdown({ options, value, onChange }) {
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
setIsOpen(!isOpen);
};
const handleOptionClick = (option) => {
// CLOSE DROPDOWN
setIsOpen(false);
// WHAT OPTION DID THE USER CLICK ON??
onChange(option);
};
const renderedOptions = options.map((option) => {
return (
<div
className='hover:g-sky-100 rounded cursor-pointer p-1'
onClick={() => handleOptionClick(option)}
key={option.value}
>
{option.label}
</div>
);
});
return (
<div className='w-48 relative'>
<div
className='flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full'
onClick={handleClick}
>
{value?.label || "Select..."} <GoChevronDown className='text-3xl' />
</div>
{isOpen && (
<div className='absolute top-full border rounded p-3 shadow bg-white w-full'>
{renderedOptions}
</div>
)}
</div>
);
}
export default Dropdown;
I thought I would add an index
to the mapping function and then compare that index to isOpen
.
I also developed an icon variable where I placed some span tags with both chevron icons.
I figured I had to put some of the elements in the second return statement inside the mapping function, but no matter how I do it I just get a blank screen.
So I have a minimal reproducible example here of what I attempted:
https://codesandbox.io/s/trusting-wind-f6dkd5?file=/src/components/Dropdown.js
But you will see that it does not look right.
There should be a Select... with an icon to the right and when you click on it some items dropdown, "red", "green", "blue" to be exact.
答案1
得分: 0
以下是您要翻译的内容:
"Since you're already holding the selected item in a useState in <App>
, you could use that value to check if the icon should be opened or closed."
"Since option.value
hold the current option from the iteration, and value.value
will hold the selected value, no need to keep track of the 'selected index';"
"Regarding OP's comment, if you want the icon
to only show it with the 'select', you can move it next to the select using a fragment and an if/else that will choose between value.label
or Select + icon
"
英文:
Since you're already holding the selected item in a useState in <App>
, you could use that value to check if the icon should be opened or closed.
const isExpanded = option.value === value?.value;
Since option.value
hold the current option from the iteration, and value.value
will hold the selected value, no need to keep track of the 'selected index'
Regarding OP's comment, if you want the icon
to only show it with the 'select', you can move it next to the select using a fragment and an if/else that will choose between value.label
or Select + icon
{
(value)
? value.label
: <React.Fragment>
{"Select..."}
"LEFT"
</React.Fragment>
}
Small demo from your fiddle
<sub>With some minor changes to make it work here in a SO snippet</sub>
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useState } = React;
function Dropdown({ options, value, onChange }) {
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
setIsOpen(!isOpen);
};
const handleOptionClick = (option) => {
// CLOSE DROPDOWN
setIsOpen(false);
// WHAT OPTION DID THE USER CLICK ON??
onChange(option);
};
const renderedOptions = options.map((option) => {
return (
<div
className="hover:g-sky-100 rounded cursor-pointer p-1"
onClick={() => handleOptionClick(option)}
key={option.value}
>
{option.label}
</div>
);
});
return (
<div className="w-48 relative">
<div
className="flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full"
onClick={handleClick}
>
{
value
? value.label
: <React.Fragment>
{"Select..."}
"LEFT"
</React.Fragment>
}
</div>
{isOpen && (
<div className="absolute top-full border rounded p-3 shadow bg-white w-full">
{renderedOptions}
</div>
)}
</div>
);
}
const Example = () => {
const [selection, setSelection] = useState(null);
const handleSelect = (option) => {
setSelection(option);
};
const options = [
{ label: "Red", value: "red" },
{ label: "Green", value: "green" },
{ label: "Blue", value: "blue" }
];
return (
<Dropdown options={options} value={selection} onChange={handleSelect} />
);
}
ReactDOM.render(<Example />, document.getElementById("react"));
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
<!-- end snippet -->
答案2
得分: 0
这是我想要的:
return (
<div className='w-48 relative'>
<div
className='flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full'
onClick={handleClick}
>
{value?.label || "选择..."}
{isOpen ? (
<GoChevronDown className='text-3xl' />
) : (
<GoChevronLeft className='text-3xl' />
)}
</div>
{isOpen && (
<div className='absolute top-full border rounded p-3 shadow bg-white w-full'>
{renderedOptions}
</div>
)}
</div>
);
通过这次重构,当单击下拉框时,Dropdown
组件将显示 GoChevronDown
图标,当未单击下拉框时,将显示 GoChevronLeft
图标。这就是我想要的效果,但我在弄清楚它时感到有些困难,有时在 JSX 中编写 JavaScript 对我来说可能会有些痛苦。对于任何混淆,我深感抱歉。
英文:
This is what I was going for:
return (
<div className='w-48 relative'>
<div
className='flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full'
onClick={handleClick}
>
{value?.label || "Select..."}
{isOpen ? (
<GoChevronDown className='text-3xl' />
) : (
<GoChevronLeft className='text-3xl' />
)}
</div>
{isOpen && (
<div className='absolute top-full border rounded p-3 shadow bg-white w-full'>
{renderedOptions}
</div>
)}
</div>
);
With this refactor, the Dropdown
component will display the GoChevronDown
icon when the dropdown is clicked and the GoChevronLeft
icon when the dropdown is not clicked. This is what I was going for, but it was a struggle to figure it out, writing JS in JSX can be sometimes painful for me. My apologies for any confusion.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论