【问题标题】:Select value doesnt change the first time I trigger onChange event when using setSate React使用 setState React 时第一次触发 onChange 事件时选择值不会改变
【发布时间】:2022-01-11 13:03:41
【问题描述】:

我有一组选择菜单,当我使用 onChange={updateValue} 事件选择一个选项时,我试图更改一个值。当我第一次选择一个选项时,选择菜单中的值没有更新。 它只会在我第二次尝试选择一个选项时发生变化。不知道我做错了什么。

编辑:我做了更多研究 (OnChange event using React JS for drop down),我相信我也需要使用 setState 更新选择的值。如果没有每个值的变量并再次设置状态,我无法弄清楚如何做到这一点。

let selectMenus = [
  {
    id: 'id1',
    name: 'name1',
    label: 'label1',
    value: '0',
    options: [
      {
        text: 'All ages',
        value: '0',
      },
      {
        text: '35 - 37 yrs',
        value: '1',
      },
    ],
    buttonLabel: 'Refresh',
  },
  {
    id: 'id2',
    name: 'name2',
    label: 'label2',
    value: '1',
    options: [
      {
        text: 'All ages',
        value: '0',
      },
      {
        text: '45 - 50 yrs',
        value: '1',
      },
    ],
    buttonLabel: 'Refresh',
  },
];

const [url, setUrl] = useState('http://localhost:5000/selectDropdowns1');

const updateValue = () => {
  setUrl('http://localhost:5000/selectDropdowns2');
};

<form>
  {selectMenus.map((select) => (
    <div key={select.id} className='select-container'>
      <label htmlFor={select.id}>{select.label}</label>
      <select id={select.id} name={select.name} value={select.value} onChange={updateValue}>
        {select.options.map((option) => (
          <option value={option.value} key={uuid()}>
            {option.text}
          </option>
        ))}
      </select>
      <button>{select.buttonLabel}</button>
    </div>
  ))}
</form>;

【问题讨论】:

    标签: javascript reactjs select onchange setstate


    【解决方案1】:

    问题是当你提供 onChange 属性来选择组件时,它变成了一个受控组件

    欲了解更多信息:React Docs - Forms #controlled components

    当您处理受控组件时,您必须为其提供一个值,并且当 onChange 触发时,它应该更新该值以正常工作。由于您没有提供完整的代码,我想您有一组附加的选择菜单和选项。

    所以在这种情况下,每个选择组件都应该有自己的 onChange 方法和自己的值才能正常工作。为了实现这一点,我们应该为仅选择选项创建另一个组件。像这样;

    function SelectComponent({ optionList, onSelected }) {
      const [value, setValue] = useState();
    
      const updateValue = ({ target }) => {
        setValue(target.value);
        if (onSelected) onSelected(target.value);
      };
    
      return (
        <>
          <label htmlFor={optionList.id}>{optionList.label}</label>
          <select
            id={optionList.id}
            name={optionList.name}
            value={value}
            onChange={updateValue}
          >
            {optionList.options.map((option) => (
              <option value={option.value} key={uuid()}>
                {option.text}
              </option>
            ))}
          </select>
          <button>{optionList.buttonLabel}</button>
        </>
      );
    }
    

    该组件接受道具; optionListonSelected

    optionList 是要渲染的选项列表

    onSelected是我们在用户选择和选项时调用的方法

    在主组件上,我们应该使用带有道具 optionListonSelected

    的选择组件更改选择部分
      return (
        <div>
          {selectMenus.map((select) => (
            <div key={select.id} className="select-container">
              <SelectComponent optionList={select} onSelected={updateValue} />
            </div>
          ))}
        </div>
      );
    

    所以整体代码是这样的:

    import { useState } from "react";
    import { v4 as uuid } from "uuid";
    
    export default function App() {
      const [url, setUrl] = useState();
    
      const updateValue = (value) => {
        setUrl(value);
      };
    
      const selectMenus = [
        {
          id: 1,
          label: "Menu 1",
          name: "menu1",
          buttonLabel: "Menu 1",
          options: [
            {
              text: "option 1",
              value: "option1"
            },
            {
              text: "option 2",
              value: "option2"
            },
            {
              text: "option 3",
              value: "option3"
            }
          ]
        },
        {
          id: 2,
          label: "Menu 2",
          name: "menu2",
          buttonLabel: "Menu 2",
          options: [
            {
              text: "option 1",
              value: "option1"
            },
            {
              text: "option 2",
              value: "option2"
            },
            {
              text: "option 3",
              value: "option3"
            }
          ]
        },
        {
          id: 3,
          label: "Menu 3",
          name: "menu3",
          buttonLabel: "Menu 3",
          options: [
            {
              text: "option 1",
              value: "option1"
            },
            {
              text: "option 2",
              value: "option2"
            },
            {
              text: "option 3",
              value: "option3"
            }
          ]
        }
      ];
    
      return (
        <div className="App">
          <h1>URL Value: {url}</h1>
          {selectMenus.map((select) => (
            <div key={select.id} className="select-container">
              <SelectComponent optionList={select} onSelected={updateValue} />
            </div>
          ))}
        </div>
      );
    }
    
    function SelectComponent({ optionList, onSelected }) {
      const [value, setValue] = useState();
    
      const updateValue = ({ target }) => {
        setValue(target.value);
        if (onSelected) onSelected(target.value);
      };
    
      return (
        <>
          <label htmlFor={optionList.id}>{optionList.label}</label>
          <select
            id={optionList.id}
            name={optionList.name}
            value={value}
            onChange={updateValue}
          >
            {optionList.options.map((option) => (
              <option value={option.value} key={uuid()}>
                {option.text}
              </option>
            ))}
          </select>
          <button>{optionList.buttonLabel}</button>
        </>
      );
    }
    

    工作示例在这里codesandbox

    【讨论】:

    • 非常感谢。是的,你是对的。同时,我用 selectMenus 数组更新了我的代码。我还将值添加到选择中。我在对象内部有值,所以我将它设置为 {select.value}。我希望我可以遍历这个选择菜单数组并从那里获取它,然后用 setState 更新它但被阻止了
    • 是的,您也可以通过向数组添加值来做到这一点(大多数时候人们解决了这些问题,包括很久以前的我),但是更新其中的值会有点困难长数组,并且由于您更新整个数组,它可能会导致一些性能问题,它会重新渲染所有组件,因此使用另一个组件和自己的状态会更好:) 另外,如果这个答案是您的解决方案,请您标记一下作为“解决方案”,因此它可以使其他人受益。
    • 嘿,我想向您展示我尝试过的另一件事。每次进行更改时,我还需要打印所有选择菜单的值,并且我也有一个默认值:stackblitz.com/edit/react-5yoau2。如果您知道另一种方法,如果您告诉我,我将不胜感激。我本来希望为通过选择菜单迭代的值创建对象,所以如果有更多,那么我不需要更改任何内容
    猜你喜欢
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 2015-08-02
    • 2019-04-06
    相关资源
    最近更新 更多