簡體   English   中英

如何從 React 的數組中 Map 幾個受控輸入復選框?

[英]How do I Map several controlled input checkboxes from an array in React?

我正在嘗試從這樣的數組中制作一些受控復選框

const subjects = [
    {
      name: 'WebDev',
      label: 'Web Development',
    },
    {
      name: 'GraphicDesign',
      label: 'Graphic Design',
    },
    {
      name: 'Engineering',
      label: 'Engineering',
    },
  ];

我想讓它們受控,所以對於選中的屬性,我需要它由 state 控制。 但是我如何遍歷它們並每次訪問 state 中的正確 object ? 我想我也許可以解析 subject.name 字符串,但這肯定不是好習慣嗎? 事實上,我也許可以在索引匹配的 state 中創建一個匹配的數組,但我不認為這是可擴展的並且嚴重依賴於正確的順序。

{subjects.map((subject, i) => (
  <div className="w-full sm:w-auto" key={i}>
  <label className="flex content-center p-3">
    <input type="checkbox" name={subject.name} value={subject.name} onChange={onInputChange} checked={????}/>
    <span className="ml-3">{subject.label}</span>
  </label>
</div>
))}

我也有其他類似的輸入。 對於他們來說,這很容易,因為我可以使用state.name來控制他們。

      <input id="name" type="text" value={state.name} onChange={onInputChange} name="name" required/>

然后我使用廣義 function 來更新輸入。 這需要使用useState() Hook

    const onInputChange = e => {

    const item = e.target.name;
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;

    setState({
      ...state,
      [item]: value,
    })
  }

React 中處理此類問題的最佳實踐是什么? 如果我可以在我的 state 中包含主題,如下所示,那就太好了。

我是否應該放棄單獨的數組並包含 state 中的所有信息?

const [state, setState] = useState({
    name:'',
    email: '',
    message: '',
    checkedSubs: {
      WebDev: false,
      GraphicDesign: false,
      Engineering: false
    },
    emailSent: false
})

謝謝!

使用多個狀態來跟蹤受試者的 state 和您的一般數據。 給每個主題一個名為check的額外屬性,它應該包含一個 boolean 值。 該值將確定復選框的選中 state。

onInputChange function 中,使用新檢查的輸入 state 更新subjects state。

添加一個具有依賴關系的useEffect掛鈎: subjects數組。 每當subjects的值發生變化時,都會觸發useEffect回調 function 內部的邏輯。 在該 function 中,根據subjects數組中的值更新您的常規 state。

最終結果將是subjects數組將確定您的輸入。 每當更改輸入時, subjects state 都會更新。 然后當subjects發生變化時,輸入將被重新渲染, data中的值將根據變化進行更新。

const ExampleComponent = () => {
  const [ subjects, setSubjects ] = useState([
    {
      name: 'WebDev',
      label: 'Web Development',
      checked: false
    },
    {
      name: 'GraphicDesign',
      label: 'Graphic Design',
      checked: false
    },
    {
      name: 'Engineering',
      label: 'Engineering',
      checked: false
    },
  ]);

  const [ data, setData ] = useState({
    name:'',
    email: '',
    message: '',
    checkedSubs: {
      WebDev: false,
      GraphicDesign: false,
      Engineering: false
    },
    emailSent: false
  });

  const onInputChange = e => {
    const item = e.target.name;
    const isChecked = e.target.checked;

    const updatedSubjects = subjects.map(subject => {
      if (subject.name === item) {
        return {
          ...subject,
          checked: isChecked
        }
      }

      return subject;
    });

    setSubjects(updatedSubjects);
  };

  useEffect(() => {
    setData({
      ...data,
      checkedSubs: subjects.reduce((acc, cur) => {
        acc[cur.name] = cur.checked;
        return acc;
      }, {})
    });
  }, [subjects]);

  return (
    subjects.map(({ name, label, checked }, i) => (
      <div className="w-full sm:w-auto" key={i}>
        <label className="flex content-center p-3">
          <input type="checkbox" name={name} value={name} onChange={onInputChange} checked={checked}/>
          <span className="ml-3">{label}</span>
        </label>
      </div>
    ))
  )
}

通用onInputChange

您當前的onInputChange處理程序根據inputname屬性更新state中的屬性。 實現這一點的最簡單方法之一是讓此處理程序像更新任何其他字段一樣更新復選框。

這意味着您的主題將成為state的頂級屬性。 只要主題名稱不可能與"email"類的表單字段相同,就可以了。 您可以將state重新排列成其他變量。

您可以將 map 轉換為您的示例格式:

// can't use variable subjects because it's already defined
const {name, email, message, emailSent, ...subjectBooleans} = state;

const formatted = {name, email, message, emailSent, subjects: subjectBooleans}

您只能獲取包含已檢查主題名稱的數組:

const checkedSubjects = subjects
  .filter(o => state[o.name])
  .map( o => o.name );

我不確定subjects數組的來源以及它是常量還是可能會改變的東西。 您可以從初始 state 中省略這些屬性,並假設undefined意味着false / unchecked。 我們通過查看state[subject.name]來查看是否檢查了一個主題,我們可以使用!!顯式轉換為boolean 更好地處理這種undefined的情況。

const MyForm = ({ subjects }) => {
  
  // removed initial values for subjects
  // you could set these, but they aren't required
  const [state, setState] = useState({
    name: "",
    email: "",
    message: "",
    emailSent: false
  });

  // no changes to this function
  const onInputChange = (e) => {
    const item = e.target.name;
    const value =
      e.target.type === "checkbox" ? e.target.checked : e.target.value;

    setState({
      ...state,
      [item]: value
    });
  };

  return (
    <form>
      <input
        id="name"
        type="text"
        value={state.name}
        onChange={onInputChange}
        name="name"
        required
      />
      {/* ... other inputs ... */}
      {subjects.map((subject, i) => (
        <div className="w-full sm:w-auto" key={i}>
          <label className="flex content-center p-3">
            <input
              type="checkbox"
              name={subject.name}
              value={subject.name}
              onChange={onInputChange}
              checked={!!state[subject.name]}
            />
            <span className="ml-3">{subject.label}</span>
          </label>
        </div>
      ))}
    </form>
  );
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM