React Hooks 和表单应用

使用React Hooks 使得表单填写逻辑的封装更简易, 本文演示常用HTML表单与Hooks的应用

React

React Hooks 与表单应用

目录

1. input 文本输入框

const App = () => {
  const [form, setForm] = useState({
    age: null,
    email: "",
  })

  const handleChange = event => {
    const { name, value } = event.target
    setForm(prevState => ({
      ...prevState,
      [name]: value,
    }))
  }

  return (
    <form>
      <label>
        Age
        <input
          type="number"
          name="age"
          value={form.age}
          onChange={handleChange}
        />
      </label>
      <label>
        Email
        <input
          type="email"
          name="email"
          value={form.email}
          onChange={handleChange}
        />
      </label>
    </form>
  )
}

2. radio 单选按钮

const CATEGORY_OPTIONS = ["Anime", "Book", "Game", "Real", "Music"]

const App = () => {
  const [form, setForm] = useState({
    category: "",
  })

  const handleChange = event => {
    const { name, value } = event.target
    setForm(prevState => ({
      ...prevState,
      [name]: value,
    }))
  }

  const categoryOptions = CATEGORY_OPTIONS.map(elem => (
    <>
      <input
        type="radio"
        name="category"
        value={elem}
        checked={form.category === elem}
        onChange={handleChange}
      />
      {elem}
      <br />
    </>
  ))

  return (
    <>
      {categoryOptions}
      <button onClick={() => console.log(form)}>提交</button>
    </>
  )
}

3. select 下拉列表

const SOURCE_OPTIONS = [
  { key: "bilibili", name: "哔哩哔哩" },
  { key: "acfun", name: "AcFun" },
  { key: "youtube", name: "Youtube" },
  { key: "netflix", name: "Netflix" },
]

const App = () => {
  const [form, setForm] = useState({
    source: "bilibili",
  })

  const handleChange = event => {
    const { name, value } = event.target
    setForm(prevState => ({
      ...prevState,
      [name]: value,
    }))
  }

  const sourceOptions = SOURCE_OPTIONS.map(elem => (
    <option value={elem.key}>{elem.name}</option>
  ))

  return (
    <>
      <select name="source" value={form.source} onChange={handleChange}>
        {sourceOptions}
      </select>
      <button onClick={() => console.log(form)}>提交</button>
    </>
  )
}

4. checkbox 复选框

4.1 Array 下标更新checked

const SOURCE_OPTIONS = [
  { key: "bilibili", name: "哔哩哔哩" },
  { key: "acfun", name: "AcFun" },
  { key: "youtube", name: "Youtube" },
  { key: "netflix", name: "Netflix" },
]

const App = () => {
  const [source, setSource] = useState(
    SOURCE_OPTIONS.map(elem => ({
      ...elem,
      checked: false, // 初始化为全不选
    }))
  )

  const handleChange = indexToUpdate => {
    // copy原state 然后更新当前下标
    const updatedState = [...source]
    updatedState[indexToUpdate].checked = !updatedState[indexToUpdate].checked

    setSource(updatedState)
  }

  const sourceOptions = source.map((elem, index) => (
    <label key={elem.key}>
      <input
        type="checkbox"
        name={elem.key}
        onChange={() => handleChange(index)}
        checked={source[index].checked}
      />
      {elem.name}
      <br />
    </label>
  ))
  return (
    <>
      {sourceOptions}
      <button onClick={() => console.log(source)}>提交</button>
    </>
  )
}

4.2 利用 Object 更新

Object则可以直接对指定的key更新, 就不用下标了. 但如果给的数据是 array of objects, 则需要先转化成 Object.

同时更新 state 时也可以直接对每一层 copy.

setSource(prevState => ({
  ...prevState,
  [name]: {
    ...prevState[name],
    checked: checked,
  },
}))
const SOURCE_OPTIONS = [
  { key: "bilibili", name: "哔哩哔哩" },
  { key: "acfun", name: "AcFun" },
  { key: "youtube", name: "Youtube" },
  { key: "netflix", name: "Netflix" },
]

const App = () => {
  // 转化成Object 且每个元素初始化checked为不选
  const initSource = SOURCE_OPTIONS.reduce(
    (acc, elem) => ({ ...acc, [elem.key]: { ...elem, checked: false } }),
    {}
  )
  const [source, setSource] = useState(initSource)

  const handleChange = event => {
    const { name, checked } = event.target

    const updatedState = { ...source }
    updatedState[name].checked = checked
    setSource(updatedState)
  }

  const sourceOptions = Object.keys(source).map(elem => (
    <label key={elem}>
      <input
        type="checkbox"
        name={elem}
        onChange={handleChange}
        checked={source[elem].checked}
      />
      {source[elem].name}
      <br />
    </label>
  ))

  return (
    <>
      {sourceOptions}
      <button onClick={() => console.log(source)}>提交</button>
    </>
  )
}