在ReactJS中使用useFormik时如何将UUID作为条目ID
在React Formik中提交表单时自动分配UUID
我在ReactJS中使用useFormik提交表单,已经定义了空值的initialValues,输入框通过value={formik.values.bookName}这类方式绑定值。现在希望提交时自动为ID分配UUID,同时让bookName、autherName等字段随用户输入值提交,但不清楚何时以及如何分配UUID。相关代码如下:
import React, { useState, useEffect } from 'react'; import { useFormik } from "formik"; import * as Yup from "yup"; import { Table, Button, Row, Col } from 'react-bootstrap'; import { v4 as uuid } from "uuid"; const getDataFromLs = () => { const data = localStorage.getItem('valueArray'); if (data) { return JSON.parse(data) } else { return []; } } const formSchema = Yup.object({ bookName: Yup.string() .required("لطفا نام کتاب را وارد نمایید") .min(3, "نام کتاب کمتر از 3 حرف نباشد"), autherName: Yup.string().required().min(4).max(10), }) const FormikYupAddBook = () => { const [valueArray, setValueArray] = useState(getDataFromLs) const [id, setId] = useState('') useEffect(() => { localStorage.setItem('valueArray', JSON.stringify(valueArray)) console.log('dddd', valueArray) }, [valueArray]) const formik = useFormik({ initialValues: { bookId: "", bookName: "", autherName: "", }, validationSchema: formSchema, onSubmit(values) { localStorage.setItem('values', JSON.stringify(formik.values)) setValueArray([...valueArray, values]) console.log('vvvvv', valueArray); } }) return ( <div> <div style={{ width: "600px" }}> <form action="/action_page.php"> <div class="input-group"> <div class="input-group-btn"> <button style={{ height: "40px", width: "100px", backgroundColor: "blue" }} class="btn btn-default text-white" type="submit">submit<i class="glyphicon glyphicon-search"></i></button> </div> <input style={{ direction: "rtl" }} type="text" class="form-control" placeholder="Search" name="search" /> </div> </form> </div> <Row> <Col md={1} style={{ backgroundColor: 'pink' }}> blue </Col> <Col md={6} style={{ backgroundColor: 'white' }}> <input class="form-control form-control-lg" type="text" placeholder=".form-control-lg" /> <Table striped bordered hover> <thead> <tr> <th>#</th> <th>نام کتاب</th> <th>نام نویسنده </th> </tr> </thead> <tbody> { valueArray.map((book) => <tr> <td>{book.bookId}</td> <td>{book.bookName}</td> <td>{book.autherName}</td> </tr> ) } </tbody> </Table> </Col> <Col md={4} > <div style={{ backgroundColor: "#E7E9EB !important", color: "black !important", padding: "8px 16px !important", border: "1px solid #ccc !important", borderRadius: "5px" }} class="container-fluid mt-3 w3-border w3-padding w3-round ws-grey" > <form action="/action_page.php"> <div class="mb-3 mt-3"> <label for="email" class="form-label">Email:</label> <input type="email" class="form-control" id="email" placeholder="Enter email" name="email" /> </div> <div class="mb-3"> <label for="pwd" class="form-label">Password:</label> <input type="password" class="form-control" id="pwd" placeholder="Enter password" name="pswd" /> </div> <div class="form-check mb-3"> <label class="form-check-label"> <input class="form-check-input" type="checkbox" name="remember" /> Remember me </label> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> <form onSubmit={formik.handleSubmit}> <div> <input name="bookId" value={formik.values.bookId} onChange={() => {setId(uuid())}} /> <input style={{ fontSize: "10px", width: "300px", height: "40px", direction: "rtl" }} className="form-control" name="bookName" placeholder="لطفا نام کتاب را وارد نمایید." value={formik.values.bookName} onChange={formik.handleChange} onBlur={formik.bookName} /> {formik.submitCount > 0 && formik.errors.bookName && ( <p>{formik.errors.bookName}</p> )} </div> <div> <input style={{ fontSize: "10px", width: "300px", height: "40px", direction: "rtl" }} name="autherName" placeholder="لطفا نام نویسنده را وارد نمایید." value={formik.values.autherName} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.submitCount > 0 && formik.errors.autherName && ( <p>{formik.errors.autherName}</p> )} </div> <button >Submit</button> </form> </Col> <Col md={1} style={{ backgroundColor: 'purple', }}> </Col> </Row> </div > ) } export default FormikYupAddBook
解决方案
不需要单独维护id状态,也不需要给bookId做输入框绑定,直接在表单提交的onSubmit函数里生成UUID,然后合并到提交的values中即可,具体步骤如下:
1. 移除不必要的代码
- 删除单独的
id状态:const [id, setId] = useState('') - 删除页面中bookId的输入框组件,因为这个ID是自动生成的,不需要用户输入
2. 修改Formik的onSubmit逻辑
在onSubmit函数里,先生成UUID,然后把它添加到提交的values对象中,再存入localStorage和状态数组:
onSubmit(values) { // 生成UUID并合并到表单值中 const bookWithId = { ...values, bookId: uuid() }; localStorage.setItem('values', JSON.stringify(bookWithId)); // 使用函数式更新确保拿到最新状态 setValueArray(prevArray => [...prevArray, bookWithId]); // 提交后重置表单 formik.resetForm(); }
3. 修正表单绑定细节
- 把bookName输入框的
onBlur={formik.bookName}改为onBlur={formik.handleBlur},否则表单校验会失效 - 给提交按钮添加
type="submit"属性,避免默认表单跳转行为
完整修改后的代码
import React, { useState, useEffect } from 'react'; import { useFormik } from "formik"; import * as Yup from "yup"; import { Table, Button, Row, Col } from 'react-bootstrap'; import { v4 as uuid } from "uuid"; const getDataFromLs = () => { const data = localStorage.getItem('valueArray'); if (data) { return JSON.parse(data) } else { return []; } } const formSchema = Yup.object({ bookName: Yup.string() .required("لطفا نام کتاب را وارد نمایید") .min(3, "نام کتاب کمتر از 3 حرف نباشد"), autherName: Yup.string().required().min(4).max(10), }) const FormikYupAddBook = () => { const [valueArray, setValueArray] = useState(getDataFromLs) useEffect(() => { localStorage.setItem('valueArray', JSON.stringify(valueArray)) }, [valueArray]) const formik = useFormik({ initialValues: { bookName: "", autherName: "", }, validationSchema: formSchema, onSubmit(values) { // 生成UUID并合并到表单数据 const bookWithId = { ...values, bookId: uuid() }; localStorage.setItem('values', JSON.stringify(bookWithId)); // 函数式更新确保状态正确 setValueArray(prev => [...prev, bookWithId]); // 重置表单 formik.resetForm(); } }) return ( <div> <div style={{ width: "600px" }}> <form action="/action_page.php"> <div className="input-group"> <div className="input-group-btn"> <button style={{ height: "40px", width: "100px", backgroundColor: "blue" }} className="btn btn-default text-white" type="submit">submit<i className="glyphicon glyphicon-search"></i></button> </div> <input style={{ direction: "rtl" }} type="text" className="form-control" placeholder="Search" name="search" /> </div> </form> </div> <Row> <Col md={1} style={{ backgroundColor: 'pink' }}> blue </Col> <Col md={6} style={{ backgroundColor: 'white' }}> <input className="form-control form-control-lg" type="text" placeholder=".form-control-lg" /> <Table striped bordered hover> <thead> <tr> <th>#</th> <th>نام کتاب</th> <th>نام نویسنده </th> </tr> </thead> <tbody> {valueArray.map((book) => ( <tr key={book.bookId}> <td>{book.bookId}</td> <td>{book.bookName}</td> <td>{book.autherName}</td> </tr> ))} </tbody> </Table> </Col> <Col md={4} > <div style={{ backgroundColor: "#E7E9EB", color: "black", padding: "8px 16px", border: "1px solid #ccc", borderRadius: "5px" }} className="container-fluid mt-3 w3-border w3-padding w3-round ws-grey" > <form action="/action_page.php"> <div className="mb-3 mt-3"> <label htmlFor="email" className="form-label">Email:</label> <input type="email" className="form-control" id="email" placeholder="Enter email" name="email" /> </div> <div className="mb-3"> <label htmlFor="pwd" className="form-label">Password:</label> <input type="password" className="form-control" id="pwd" placeholder="Enter password" name="pswd" /> </div> <div className="form-check mb-3"> <label className="form-check-label"> <input className="form-check-input" type="checkbox" name="remember" /> Remember me </label> </div> <button type="submit" className="btn btn-primary">Submit</button> </form> </div> <form onSubmit={formik.handleSubmit}> <div> <input style={{ fontSize: "10px", width: "300px", height: "40px", direction: "rtl" }} className="form-control" name="bookName" placeholder="لطفا نام کتاب را وارد نمایید." value={formik.values.bookName} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.submitCount > 0 && formik.errors.bookName && ( <p>{formik.errors.bookName}</p> )} </div> <div> <input style={{ fontSize: "10px", width: "300px", height: "40px", direction: "rtl" }} name="autherName" placeholder="لطفا نام نویسنده را وارد نمایید." value={formik.values.autherName} onChange={formik.handleChange} onBlur={formik.handleBlur} /> {formik.submitCount > 0 && formik.errors.autherName && ( <p>{formik.errors.autherName}</p> )} </div> <button type="submit">Submit</button> </form> </Col> <Col md={1} style={{ backgroundColor: 'purple' }}></Col> </Row> </div > ) } export default FormikYupAddBook
关键说明
- UUID生成时机:在
onSubmit里生成,确保每次提交都能得到唯一ID,不需要提前存储 - 状态更新:使用
setValueArray(prev => [...prev, bookWithId])的函数式更新,避免闭包导致的旧状态问题 - 表单重置:提交后调用
formik.resetForm()清空表单,提升用户体验 - 代码简化:移除了无用的bookId输入框和单独的id状态,逻辑更清晰
内容的提问来源于stack exchange,提问作者hhamidy
相关产品推荐
相关产品推荐

