使用Redux表单在React中管理表单状态

介绍 (Introduction)

redux-form is a great way of managing forms that are powered by Redux. It is a Higher-Order-Component (HOC) that uses react-redux to make sure HTML forms in React use Redux to store all of its state.

redux-form是管理由Redux支持的表单的好方法。 它是一个使用React -redux来确保React中HTML表单使用Redux来存储其所有状态的高阶组件(HOC)。

redux-form has the following components to help you build your applications:

redux-form具有以下组件可帮助您构建应用程序:

  • formReducer(): This is a function that tells how to update the Redux store based on changes coming from the application; those changes are described by Redux actions. formReducer has to be mounted on the Redux state at form.

    formReducer() :这是一个函数,该函数指示如何根据应用程序中的更改来更新Redux存储。 这些更改由Redux操作描述。 formReducer必须在form处安装在Redux状态。

  • reduxForm(): The reduxForm() function is a higher-order component takes a configuration object and it always returns a new function. It is used to wrap the form component and bind user interaction to the Redux dispatch actions.

    reduxForm()reduxForm()函数是带有配置对象的高阶组件,它总是返回一个新函数。 它用于包装表单组件并将用户交互绑定到Redux派发操作。

  • The <Field/> component: A component that lives inside your wrapped form component. It serves as a way to connect the input elements in a form to the redux-form logic. In other words, it’s the way we get the input from what users type.

    <Field/>组件:位于包装表单组件中的组件。 它用作将表单中的输入元素连接到redux-form logic 。 换句话说,这就是我们从用户键入的内容中获取输入的方法。

You can read more about the redux-form API in its documentation.

您可以在文档中阅读有关redux-form API的更多信息。

In this tutorial, you’ll use redux-form to build a form with validation and connect it to the Redux store.

在本教程中,您将使用redux-form构建带有验证的表单并将其连接到Redux存储。

先决条件 (Prerequisites)

To complete this tutorial, you will need:

要完成本教程,您将需要:

步骤1 –建立专案 (Step 1 – Creating the Project)

We’ll be building a React app with the create-react-app package. create-react-app allows you to create React apps with no build configuration. You can use create-react-app by running the terminal command that follows. It automatically creates a React app for you in a folder titled contact-redux.

我们将使用create-react-app包构建一个React应用。 create-react-app允许您创建没有构建配置的React应用。 您可以通过运行以下终端命令来使用create-react-app 。 它会自动在名为contact-redux的文件夹中为您创建一个React应用。

  • npx create-react-app contact-redux

    npx create-react-app contact-redux

It’s important to note that npx only works with versions of npm that are 5.2 and above. If you have a version lower than that and would still like to use create-react-app on your computer. Run the terminal commands below to install create-react-app and start a React app.

重要的是要注意, npx仅适用于5.2及更高版本的npm版本。 如果您的版本低于该版本,并且仍想在计算机上使用create-react-app 。 运行以下终端命令以安装create-react-app并启动React应用。

  • npm install -g create-react-app

    npm install -g create-react-app
  • create-react-app contact-redux

    create-react-app contact-redux

Navigate to the directory and start the development server to ensure everything works. Run the following command to start the newly created React app in development mode:

导航到目录并启动开发服务器以确保一切正常。 运行以下命令以在开发模式下启动新创建的React应用程序:

  • npm start

    npm开始

You’ll see the following in your browser:

您将在浏览器中看到以下内容:

We now have a React app up and running.

现在,我们已经启动并运行了一个React应用。

Execute the following command to add the dependencies you’ll need for the form.

执行以下命令以添加表单所需的依赖项。

  • npm install --save redux react-redux redux-form

    npm install-保存redux react-redux redux-form
  • redux - A state container and it’s a prerequisite for redux-form to work.

    redux-状态容器,它是redux-form起作用的先决条件。

  • react-redux - React Redux is the official React bindings for Redux and it’s also a prerequisite for redux-form to work

    react-redux -React Redux是Redux的官方React绑定,它也是redux-form起作用的前提

  • redux-form - The package in use for this tutorial.

    redux-form-本教程使用的软件包。

Once that’s been installed, you can work on the contact form.

安装完成后,您可以使用联系表。

第2步-创建表单 (Step 2 – Creating the Form)

We’ll add a Bulma CDN link to the index.html file so as to add some default styling. Open the public/index.html file and add the following line of code to the head tag:

我们将Bulma CDN链接添加到index.html文件,以便添加一些默认样式。 打开public/index.html文件,并将以下代码行添加到head标记中:

public/index.html
public / index.html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">

We’ll be making some edits to the src/App.js file now. Open up the src/App.js file and add the line of code below at the top of the file.

现在,我们将对src/App.js文件进行一些编辑。 打开src/App.js文件,并在文件顶部下方添加以下代码行。

src/App.js
src / App.js
import { reduxForm, Field } from 'redux-form';

Next, go to the render() function, and modify it with the following code:

接下来,转到render()函数,并使用以下代码对其进行修改:

src/App.js
src / App.js
render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React x redux-form</h1>
        </header>
        <div className="container">
          <p className="App-intro">
            Contact Form
          </p>
          <SignInForm />
        </div>
      </div>
    );
  }

The introductory text has been changed and most importantly we added a <SignInForm /> component which we’ll create below. It’s going to be a simple component that returns the form we need and it will be hooked up to redux-form component. In the same src/App.js file, type out this code below just before the declaration of class App extends Component.

介绍性文本已更改,最重要的是,我们添加了一个<SignInForm />组件,该组件将在下面创建。 这将是一个简单的组件,它返回我们所需的表单,并将其连接到redux-form组件。 在同一src/App.js文件中,在class App extends Component的声明class App extends Component之前,在下面键入此代码。

src/App.js
src / App.js
let SignInForm = props => {
  return <form className="form">
    <div className="field">
      <div className="control">
        <label className="label">First Name</label>
        <Field className="input" name="firstName" component="input" type="text" placeholder="First Name"/>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="label">Last Name</label>
        <Field className="input" name="lastName" component="input" type="text" placeholder="Last Name"/>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="label">Email</label>
        <Field className="input" name="email" component="input" type="email" placeholder="Email Address"/>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="label">Proficiency</label>
        <div className="select">
          <Field className="input" name="proficiency" component="select">
            <option />
            <option value="beginner">Beginner Dev</option>
            <option value="intermediate">Intermediate Dev</option>
            <option value="expert">Expert Dev</option>
          </Field>
        </div>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="label">Age</label>
        <Field className="input" name="age" component="input" type="number" placeholder="Age"/>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="checkbox">
          <Field name="saveDetails" id="saveDetails" component="input" type="checkbox"/>
          Save Details
        </label>
      </div>
    </div>

    <div className="field">
      <div className="control">
        <label className="label">Message</label>
        <Field className="textarea" name="message" component="textarea" />
      </div>
    </div>

    <div className="field">
      <div className="control">
        <button className="button is-link">Submit</button>
      </div>
    </div>

  </form>;
};

In this code, we set up a minimal contact form, which asks the user for information such as First Name, Last Name, and Age. The interesting bit in this form is the Field component.

在此代码中,我们设置了一个最小联系表,该表单要求用户提供诸如名,姓和年龄的信息。 这种形式的有趣之处在于Field组件。

The Field component comes from the redux-form package and it’s how we write the input field. The type prop indicates what type of input it should be, that is, a radio input, a checkbox input, a text input or an email input. The component prop determines what type of input field it should be, it could be input, textarea or select tags and the name prop is what will be used to identify the state of the fields in the redux store which we’ll create below.

Field组件来自redux-form包,这就是我们编写input字段的方式。 type prop指示输入应为哪种类型,即radio输入, checkbox输入, text输入或email输入。 prop component确定应该是什么类型的输入字段,可以是inputtextareaselect标签,而name prop就是用来标识Redux存储区中字段状态的名称(我们将在下面创建)。

So in order to use the form hooked up to redux-form, we need to have some sort of Redux store created already and that’s what we’re going to do next.

因此,为了使用连接到redux-form的表单,我们需要已经创建了某种Redux存储,这就是我们下一步要做的。

第3步–设置Redux存储 (Step 3 – Setting up a Redux Store)

We need a Redux store in which we can connect the form component (SignInForm) we created. Let’s start by importing the redux package. Open the src/index.js file and add the following lines of code in which we are basically importing redux to the React app.

我们需要一个Redux存储,我们可以在其中连接我们创建的表单组件( SignInForm )。 让我们从导入redux包开始。 打开src/index.js文件,并添加以下代码行,其中我们基本上将redux导入到React应用程序中。

src/index.js
src / index.js
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { reducer as formReducer } from 'redux-form';

The first line of code imports createStore and combineReducers. createStore helps to create a Redux store that holds the complete state tree of your app and the combineReducers helps to manage all of your reducer functions into one single helper function which can then be passed into createStore. You can read more about these function on the Redux API reference page.

第一行代码导入createStorecombineReducerscreateStore帮助创建一个Redux存储,该存储包含应用程序的完整状态树,而combineReducers帮助将所有reducer功能管理到一个单一的helper函数中,然后可以将其传递到createStore 。 您可以在Redux API 参考页面上阅读有关这些功能的更多信息。

The second line of code imports Provider from react-redux. Provider helps to pass the state of the store to all container components in the app and we’ll demonstrate how that works later.

第二行代码从react-redux导入ProviderProvider有助于将商店的状态传递给应用程序中的所有容器组件,稍后我们将演示其工作原理。

The third line of code imports reducer as formReducer and that’s what we’re going to use to hook up our form to the Redux store.

第三行代码将reducer作为formReducer ,这就是我们要用来将表单连接到Redux存储的内容。

Next, we’ll create the actual Redux store and make sure it’s applicable to all container components by using the Provider component. Edit the src/index.js file with the following code block.

接下来,我们将创建实际的Redux存储,并使用Provider组件确保其适用于所有容器组件。 使用以下代码块编辑src/index.js文件。

src/index.js
src / index.js
import React from 'react';
import ReactDOM from 'react-dom';

import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { reducer as formReducer } from 'redux-form';

import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

const rootReducer = combineReducers({
  form: formReducer,
});

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

registerServiceWorker();

In the code block above, we use the combineReducers function to connect the formReducer from the form to the Redux store. It’s basically used to update any of our state in response to actions, which in this case, are changes to the form. The next line of code is used to create a store by using createStore from Redux.

在上面的代码块中,我们使用combineReducers函数将formReducer从表单连接到Redux存储。 它基本上用于更新我们的任何状态以响应动作,在这种情况下,就是对表单的更改。 下一行代码用于通过使用Redux中的createStore创建商店。

This newly created store is then made available to all parts of the app with the help of Provider which is wrapped around the App component and it also accepts a prop of store which is the store that was created above.

然后,在Provider的帮助下,该新创建的商店可供应用程序的所有部分使用,该Provider包裹在App组件周围,并且它还接受商店的道具,即上面创建的store

Let’s go back to the form and finally connect it to the store.

让我们回到表格,最后将其连接到商店。

##步骤4 –将表单连接到redux-form (## Step 4 – Connecting the Form to redux-form)

We have our form component but it’s not connected to redux-form yet. Let’s fix that. Type out this code block below just before the class App extends Component and immediately after the declaration of the SignInForm presentational component.

我们有表单组件,但尚未连接到redux-form 。 让我们修复它。 在class App extends Component和SignInForm呈现组件的声明之后立即在下面键入此代码块。

src/index.js
src / index.js
SignInForm = reduxForm({
  form: 'signIn',
})(SignInForm);

In the code block above, SignInForm is made into a redux-connected form using the reduxForm Higher Order Component. This means that our form is now hooked up to the store. One thing to note is the config key form, it is used as an identifier and it’s used to provide a unique name for the form component. If they were multiple forms, then you’d need to use separate names so as to better manage their different states.

在上面的代码块, SignInForm制成使用一个终极版,连接形式reduxForm高阶分量。 这意味着我们的表单现在已连接到商店。 要注意的一件事是config key form ,它用作标识符,用于为form组件提供唯一的名称。 如果它们是多种形式,则需要使用单独的名称,以便更好地管理它们的不同状态。

The next thing we have to do is configure what happens when we click on the Submit button. In an ideal app, you’d want to send data to a remote API or some databases but for the purpose of demonstrations, we’ll log the form data into the browser console. To do that we’ll need to get the form data from the props and store them somewhere.

接下来要做的是配置单击“提交”按钮时发生的情况。 在理想的应用程序中,您希望将数据发送到远程API或某些数据库,但是出于演示的目的,我们会将表单数据记录到浏览器控制台中。 为此,我们需要从道具中获取表单数据并将其存储在某处。

Inside the SignInForm component, add the line of code below just above the return statement.

SignInForm组件内部,在return语句的正下方添加以下代码行。

src/index.js
src / index.js
const { handleSubmit } = props;
  return <form **onSubmit={handleSubmit}** className="form">

The props in the SignInForm form is destructured into handleSubmit. The handleSubmit function will then be used in the form as a handler for the onSubmit event when the submit button is clicked on.

SignInForm形式的props被分解为handleSubmit 。 然后,当单击“提交”按钮时, handleSubmit函数将在窗体中用作onSubmit事件的处理程序。

Finally, inside the App component in the src/App.js file, we’ll create a function that logs the form data to the browser console. Add the code block below to the file just before the render() function.

最后,在src/App.js文件的App组件内部,我们将创建一个将表单数据记录到浏览器控制台的函数。 将下面的代码块添加到文件中render()函数之前。

src/App.js
src / App.js
handleSignIn = values => {
        console.log(values);
    };

Then add the handleSignIn function as an event handler for the SignInForm component. redux-form automatically will ascertain that the data gotten from the form, which is essentially the SignInForm component should be logged to the console thanks to the handleSubmit function above.

然后将handleSignIn函数添加为SignInForm组件的事件处理程序。 由于上面的handleSubmit函数, redux-form自动确定从表单(本质上是SignInForm组件)获取的数据应记录到控制台。

src/App.js
src / App.js
<SignInForm onSubmit={this.handleSignIn} />

You can now start the app by running the npm start terminal command. Fill out the form, click on submit and you’ll see the values logged to the console.

现在,您可以通过运行npm start terminal命令来启动应用程序。 填写表格,单击提交,您将看到记录到控制台的值。

步骤5 –添加验证 (Step 5 – Adding Validations)

Validations are important when it comes to building forms and redux-form ships with some validation features and we’re going to implement that now. In the src/App.js file, type in the code block below.

在构建具有某些验证功能的表单和redux-form船时,验证非常重要,我们现在将实现它。 在src/App.js文件中,键入下面的代码块。

src/App.js
src / App.js
const validate = val => {
  const errors = {};
  if (!val.firstName) {
    console.log('First Name is required');
    errors.firstName = 'Required';
  }
  if (!val.lastName) {
    console.log('Last Name is required');
    errors.lastName = 'Required';
  }
  if (!val.email) {
    console.log('email is required');
    errors.email = 'Required';
  } else if (!/^.+@.+$/i.test(val.email)) {
    console.log('email is invalid');
    errors.email = 'Invalid email address';
  }
  if (!val.age) {
    errors.age = 'Required'
  } else if (isNaN(Number(val.age))) {
    errors.age = 'Must be a number'
  } else if (Number(val.age) < 18) {
    errors.age = 'Sorry, you must be at least 18 years old'
  }
  return errors;
};

The validate function is used to check for validation errors in the form. The val parameter will be used to check the validation of different fields. We first check if the errors object is empty, an empty object obviously means there are no errors. We then use conditional logic to check if a field is empty, if it is, you throw the corresponding error. In the code block above, we’re only doing validations for firstName, lastName, email, and age. In the email validation conditional, we check if it’s empty and also check if it’s a valid email by using regex and in the age validation conditional, we check if it’s empty, a number and if the user is less than 18.

validate函数用于检查表单中的验证错误。 val参数将用于检查不同字段的有效性。 我们首先检查errors对象是否为空,显然,空对象意味着没有错误。 然后,我们使用条件逻辑检查字段是否为空,如果为空,则抛出相应的错误。 在上面的代码块中,我们仅对firstNamelastNameemailage进行验证。 在email验证条件中,我们使用regex检查它是否为空,还检查它是否为有效电子邮件;在age验证条件中,我们检查它是否为空,一个数字以及用户是否小于18。

Next, we’ll register our validation function to redux-form so that it can begin using it to carry out validation tests. Add the validate function to the redux-form Higher Order Component:

接下来,我们将验证功能注册到redux-form以便它可以开始使用它来执行验证测试。 将validate函数添加到redux-form Higher Order组件:

src/index.js
src / index.js
SignInForm = reduxForm({
  form: 'signIn',
  validate,
})(SignInForm);

Now that we have our validation function ready and registered in the redux-form HOC, build a reusable component that displays errors whenever there are any and using that newly created component in our forms.

现在,我们已经准备好验证功能并在redux-form HOC中注册,我们将构建一个可重用的组件,该组件在有任何错误时显示错误,并在表单中使用该新创建的组件。

src/index.js
src / index.js
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
  <div>
    <div className="control">
      <label className="field">{label}</label>
      <input className="input" {...input} placeholder={label} type={type}/>
      {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
    </div>
  </div>
)

The renderField component takes in props of the input object, a label, the type of input and meta which is a redux-form property. The line {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))} means that an error message should show if there are any errors when the form field has been clicked/focused on. Also, the form will not be submitted if there are any errors.

renderField组件接受input对象的属性, label ,输入typemeta ,后者是redux-form属性。 {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}意味着要显示一条错误消息,如果有任何错误单击/重点放在表单字段时。 此外,如果有任何错误,将不会提交该表格。

Now, if you check the form and try to enter any invalid input or skip the fields that have validation tests, you should error messages underneath the form.

现在,如果您检查表单并尝试输入任何无效输入或跳过具有验证测试的字段,则应该在表单下方显示错误消息。

结论 (Conclusion)

In this tutorial, you built a form with redux-form and connected it to the Redux store. You added synchronous validation on the form without the need for external schema validators.

在本教程中,您使用redux-form构建了一个表单,并将其连接到Redux存储。 您在表单上添加了同步验证,而无需外部模式验证器。

You can read more about redux-form on the official site and you can go through their examples to explore further.

您可以在官方网站上阅读有关redux-form更多信息,并可以通过他们的示例进行进一步的探索。

You can find the completed code for this tutorial on GitHub.

您可以在GitHub找到本教程的完整代码。

翻译自: https://www.digitalocean.com/community/tutorials/managing-form-state-in-react-with-redux-form

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值