【问题标题】:What is best way to create forms in react?在反应中创建表单的最佳方法是什么?
【发布时间】:2019-11-21 07:14:17
【问题描述】:

我是反应的初学者。我有以下代码:

import React, { useState, useEffect } from 'react';
import { Card, Form, Button } from 'react-bootstrap';
import Axios from 'axios'

export function StudentForm({ student, onSuccess, onError, setState }) {
    const url = `http://localhost:9899/api/StudentData`;

    const intialStudent = { Firstname: '', Middlename: '', Lastname: '', DOB: '', Gender: '' };

    const [Student, setStudent] = useState(intialStudent);

    useEffect(() => {
        setStudent(student ? student : intialStudent);
    }, [student]);

    const SaveData = function (studentData) {

        if (student._id) {
            Axios.post(url, { ...studentData }, { headers: { 'accept': 'application/json' } })
                .then(res => {
                    setState(null);
                    onSuccess(res);

                })
                .catch(error => {
                    alert('Error To Edit data');
                });
        }
        else {
            Axios.post(url, studentData, { headers: { 'accept': 'application/json' } })
                .then(res => {
                    setState(null);
                    onSuccess(res);
                })
                .catch(err => onError(err));
        }
    }
    return (
        <Card>
            <Card.Header><h5>{student ? "Edit" : "Add"} Student</h5></Card.Header>
            <Card.Body>
                <Form onSubmit={(e) => { e.preventDefault(); SaveData(Student); }}>
                    <Form.Group><Form.Control type="text" name="Firstname" placeholder="Firstname" value={Student.Firstname} onChange={e => { setStudent({ ...Student, Firstname: e.target.value }) }} /></Form.Group>
                    <Form.Group><Form.Control type="text" name="Middlename" placeholder="Middlename" value={Student.Middlename} onChange={e => setStudent({ ...Student, Middlename: e.target.value })} /></Form.Group>
                    <Form.Group><Form.Control type="text" name="Lastname" placeholder="Lastname" value={Student.Lastname} onChange={e => setStudent({ ...Student, Lastname: e.target.value })} /></Form.Group>
                    <Form.Group><Form.Control type="date" name="DOB" placeholder="DOB" value={Student.DOB} onChange={e => setStudent({ ...Student, DOB: e.target.value })} /></Form.Group>
                    <Form.Group><Form.Control type="text" name="Gender" placeholder="Class" value={Student.Gender} onChange={e => setStudent({ ...Student, Gender: e.target.value })} /></Form.Group>
                    <Button variant="primary" type="submit">Submit</Button>
                </Form>
            </Card.Body>
        </Card>
    );
}

在上面的代码中,我在每个字段的更改事件上设置状态。因此,当我更改任何字段时,它会一次又一次地渲染。如果它是大表格,那么重新渲染可能需要很长时间,所以有没有更好的方法来创建处理这种情况,或者任何最好的react 使用表单的做法?

【问题讨论】:

  • 好问题,顺便说一句,如果不再次呈现表单,您将无法看到表单的反映变化。所以这是唯一的方法,即更新 onchange 事件的表单。顺便说一句,您的表格有多大取决于可以计算出的某种方式。

标签: javascript reactjs react-redux


【解决方案1】:

您只能对所有 onChanges 使用一个函数。看起来像这样;

<Form.Group>
  <Form.Control
     type="text"
     name="Firstname"
     placeholder="Firstname"
     value={Student.Firstname}
     onChange={handleChange} 
  />
</Form.Group>

这是你的 handleChange 函数;

const handleChange = e => {
  const {name, value} = e.target
  setValues({...values, [name]: value})
}

这是你的状态;

const [values, setValues] = useState({
  Firstname: "", 
  Middlename: "", 
  Lastname: "",
  DOB: "",
  Gender: ""
})

我认为这种方式用更少的代码更有效。

【讨论】:

  • 您已经完成了类似的渲染操作,即在每次输入更改时,整个表单都会被渲染。
【解决方案2】:

在 react 中管理表单是一项复杂到足以将其委托给库的任务。 Alo,大表单不是功能组件的好选择,因为您概述的问题。当然,您可以花时间对其进行调整,但我认为这种努力可能不值得。

我个人的建议是尝试使用众多的 react 表单库之一。我个人喜欢的是Formik

如果您想自己管理表单,我建议您将表单封装在有状态组件上,并在需要时使用 key 属性更容易重置。

另一种选择是使用 memoization,例如使用 react.memo。但这并不能保证成功,除非您的数据具有适当的形状。这意味着,可以在它们自身之间进行比较的简单值,而不是数组、函数、对象。

【讨论】:

    【解决方案3】:

    您必须在输入更改时重新渲染表单,但是当您确保 onChange 函数不会更改每次渲染的引用并且您的输入是纯组件时,您不需要重新渲染每个输入(使用 React .memo 用于功能组件,继承自 React.PureComponent 用于类组件)。

    这是优化输入的示例。

    const {
      useEffect,
      useCallback,
      useState,
      memo,
      useRef,
    } = React;
    function App() {
      return <StudentForm />;
    }
    //put initial student here so it doesn't change reference and quits the linter
    //  in useEffect
    const initialStudent = {
      Firstname: '',
      Middlename: '',
    };
    function StudentForm({ student }) {
      const [Student, setStudent] = useState(initialStudent);
      //useCallback so onChange is not re created and causes re rendering
      //  of components that didn't change
      const onChange = useCallback(
        (key, value) =>
          setStudent(student => ({ ...student, [key]: value })),
        []
      );
    
      useEffect(() => {
        setStudent(student ? student : initialStudent);
      }, [student]);
    
      const SaveData = function(studentData) {
        console.log('saving data:', studentData);
      };
      return (
        <form
          onSubmit={e => {
            e.preventDefault();
            SaveData(Student);
          }}
        >
          <InputContainer
            type="text"
            name="Firstname"
            placeholder="Firstname"
            value={Student.Firstname}
            stateKey="Firstname" //provide state key
            onChange={onChange}
          />
          <InputContainer
            type="text"
            name="Middlename"
            placeholder="Middlename"
            value={Student.Middlename}
            stateKey="Middlename"
            onChange={onChange}
          />
          <button type="submit">Submit</button>
        </form>
      );
    }
    //make this a pure component (does not re render if nothing changed)
    const InputContainer = memo(function InputContainer({
      type,
      name,
      placeholder,
      value,
      onChange,
      stateKey,
    }) {
      const rendered = useRef(0);
      rendered.current++;
      return (
        <div>
          <div>{rendered.current} times rendered.</div>
          <input
            type={type}
            name={name}
            value={value}
            placeholder={placeholder}
            onChange={e =>
              //pass state key and new value to onChange
              onChange(stateKey, e.target.value)
            }
          />
        </div>
      );
    });
    
    ReactDOM.render(<App />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多