需要重构以同时使用GoChevronDown和GoChevronLeft。

huangapple go评论58阅读模式
英文:

Need to refactor to use both GoChevronDown and GoChevronLeft

问题

我有一个需要重构的DropDown组件,根据用户点击选择标签,我需要使用GoChevronDownGoChevronLeft进行重构。我已经尝试了自己的方法,但始终只得到一个空白屏幕:

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 &quot;react&quot;;
import { GoChevronDown } from &quot;react-icons/go&quot;;

function Dropdown({ options, value, onChange }) {
  const [isOpen, setIsOpen] = useState(false);

  const handleClick = () =&gt; {
    setIsOpen(!isOpen);
  };

  const handleOptionClick = (option) =&gt; {
    // CLOSE DROPDOWN
    setIsOpen(false);
    // WHAT OPTION DID THE USER CLICK ON??
    onChange(option);
  };

  const renderedOptions = options.map((option) =&gt; {
    return (
      &lt;div
        className=&#39;hover:g-sky-100 rounded cursor-pointer p-1&#39;
        onClick={() =&gt; handleOptionClick(option)}
        key={option.value}
      &gt;
        {option.label}
      &lt;/div&gt;
    );
  });

  return (
    &lt;div className=&#39;w-48 relative&#39;&gt;
      &lt;div
        className=&#39;flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full&#39;
        onClick={handleClick}
      &gt;
        {value?.label || &quot;Select...&quot;} &lt;GoChevronDown className=&#39;text-3xl&#39; /&gt;
      &lt;/div&gt;
      {isOpen &amp;&amp; (
        &lt;div className=&#39;absolute top-full border rounded p-3 shadow bg-white w-full&#39;&gt;
          {renderedOptions}
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );
}

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 &lt;App&gt;, 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 
    : &lt;React.Fragment&gt;
        {&quot;Select...&quot;}
        &quot;LEFT&quot;
      &lt;/React.Fragment&gt;
}

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 = () =&gt; {
    setIsOpen(!isOpen);
  };

  const handleOptionClick = (option) =&gt; {
    // CLOSE DROPDOWN
    setIsOpen(false);
    // WHAT OPTION DID THE USER CLICK ON??
    onChange(option);
  };

  const renderedOptions = options.map((option) =&gt; {
    return (
      &lt;div
        className=&quot;hover:g-sky-100 rounded cursor-pointer p-1&quot;
        onClick={() =&gt; handleOptionClick(option)}
        key={option.value}
      &gt;
        {option.label}
      &lt;/div&gt;
    );
  });

  return (
    &lt;div className=&quot;w-48 relative&quot;&gt;
      &lt;div
        className=&quot;flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full&quot;
        onClick={handleClick}
      &gt;
        {
          value 
            ? value.label 
            : &lt;React.Fragment&gt;
                {&quot;Select...&quot;}
                &quot;LEFT&quot;
              &lt;/React.Fragment&gt;
        }
      &lt;/div&gt;
      {isOpen &amp;&amp; (
        &lt;div className=&quot;absolute top-full border rounded p-3 shadow bg-white w-full&quot;&gt;
          {renderedOptions}
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );
}

const Example = () =&gt; {

    const [selection, setSelection] = useState(null);

    const handleSelect = (option) =&gt; {
      setSelection(option);
    };

    const options = [
      { label: &quot;Red&quot;, value: &quot;red&quot; },
      { label: &quot;Green&quot;, value: &quot;green&quot; },
      { label: &quot;Blue&quot;, value: &quot;blue&quot; }
    ];
    return (
      &lt;Dropdown options={options} value={selection} onChange={handleSelect} /&gt;
    );
}
ReactDOM.render(&lt;Example /&gt;, document.getElementById(&quot;react&quot;));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;react&quot;&gt;&lt;/div&gt;

<!-- 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 (
    &lt;div className=&#39;w-48 relative&#39;&gt;
      &lt;div
        className=&#39;flex justify-between items-center cursor-pointer border rounded p-2 shadow bg-white w-full&#39;
        onClick={handleClick}
      &gt;
        {value?.label || &quot;Select...&quot;}
        {isOpen ? (
          &lt;GoChevronDown className=&#39;text-3xl&#39; /&gt;
        ) : (
          &lt;GoChevronLeft className=&#39;text-3xl&#39; /&gt;
        )}
      &lt;/div&gt;
      {isOpen &amp;&amp; (
        &lt;div className=&#39;absolute top-full border rounded p-3 shadow bg-white w-full&#39;&gt;
          {renderedOptions}
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );

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.

huangapple
  • 本文由 发表于 2023年7月12日 21:58:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76671391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定