介绍 (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 atform
.formReducer()
:这是一个函数,该函数指示如何根据应用程序中的更改来更新Redux存储。 这些更改由Redux操作描述。formReducer
必须在form
处安装在Redux状态。reduxForm()
: ThereduxForm()
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 theredux-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:
要完成本教程,您将需要:
A local development environment for Node.js. Follow How to Install Node.js and Create a Local Development Environment
Node.js的本地开发环境。 遵循如何安装Node.js和创建本地开发环境
步骤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
标记中:
<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
文件,并在文件顶部下方添加以下代码行。
import { reduxForm, Field } from 'redux-form';
Next, go to the render()
function, and modify it with the following code:
接下来,转到render()
函数,并使用以下代码对其进行修改:
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
之前,在下面键入此代码。
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
确定应该是什么类型的输入字段,可以是input
, textarea
或select
标签,而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应用程序中。
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.
第一行代码导入createStore
和combineReducers
。 createStore
帮助创建一个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
导入Provider
。 Provider
有助于将商店的状态传递给应用程序中的所有容器组件,稍后我们将演示其工作原理。
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
文件。
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呈现组件的声明之后立即在下面键入此代码块。
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
语句的正下方添加以下代码行。
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()
函数之前。
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
组件)获取的数据应记录到控制台。
<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
文件中,键入下面的代码块。
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
对象是否为空,显然,空对象意味着没有错误。 然后,我们使用条件逻辑检查字段是否为空,如果为空,则抛出相应的错误。 在上面的代码块中,我们仅对firstName
, lastName
, email
和age
进行验证。 在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组件:
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中注册,我们将构建一个可重用的组件,该组件在有任何错误时显示错误,并在表单中使用该新创建的组件。
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
,输入type
和meta
,后者是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.
翻译自: https://www.digitalocean.com/community/tutorials/managing-form-state-in-react-with-redux-form