开始之前
阅读本文需要对以下几项有一定了解
ECMAScript 6
文章中大量用到了 ES6 语法,比如解构赋值和函数参数默认值、剩余参数、展开语法、箭头函数等。
Hooks
React 在 16.8 版本中推出了 Hooks,它允许你在“函数组件”中使用“类组件”的一些特性。
React 本身提供了一些 Hooks,比如 useState、useReducer 等。通过在一个以“use”作为命名起始的函数中调用这些 Hooks,就得到了一个 custom Hook(自定义 Hook)。
Custom Hooks 允许我们把任何逻辑封装到其中,以便于复用足够小的组件逻辑。
Controlled Components
当我们把像 <input> <textarea> 和 <select> 这样的 HTML 元素本身的状态交给 React state 去管理,我们就得到了一个“受控组件”。
styled-components
一个与 React 契合良好的 CSS in JS 库。它允许你使用 JS 编写样式,并编译成纯 CSS 文件。
下面代码中所有的样式都是使用它编写的。如果对代码中样式的实现不是很感兴趣的话, 这个可以跳过。
代码实现
Input 组件
首先我们需要实现一个 Input 组件,我们将在该组件的基础上进行输入、校验并提示。
Input.js
import React from 'react';import PropTypes from 'prop-types';import styled from 'styled-components';const Wrap = styled.div({ display: 'flex', flexDirection: 'column', label: { display: 'flex', alignItems: 'center' }, input: { marginLeft: 8, }, p: { color: 'red', },});function Input({ label, type, helperText, error, ...otherProps }) { return ( <Wrap> <label> {label}: <input {...otherProps} type={type} /> </label> {error && <p>{helperText}</p>} </Wrap> );}Input.propTypes = { label: PropTypes.string, type: PropTypes.string, helperText: PropTypes.string, error: PropTypes.bool,};export default Input;
该组件主要接收以下几个 props:
label label 标签的文本 type 赋值给原生 input 标签的 type 属性 error 数据类型为 Boolean,如果为 true 则表示当前表单域有错误,即验证不通过 helperText 当前表单域验证不通过时,显示在表单域下方的提示文字 otherProps props 中除了上述四个以外的其他属性,全部赋值给原生 input 标签Custom Hook
有了 UI 组件之后,就可以开始实现我们的自定义 Hook 了。
useInput.js
import { useState } from 'react';export default function useInput({ initValue = '', helperText = '', validator = () => true, validateTriggers = ['onChange'],} = {}) { // 保存用户输入的值,使用 initValue 作为初始值 const [value, setValue] = useState(initValue); // Boolean 类型,表示当前表单项的验证状态 const [error, setError] = useState(false); function onChange(e) { const { value } = e.target; setValue(value); // 根据 validateTriggers 的选项,决定是否要在 onChange 里进行校验 if (validateTriggers.includes('onChange')) { setError(!validator(value)); } } /** * 根据 validateTriggers 生成相应的事件处理器 */ function createEventHandlers() { const eventHandlers = {}; validateTriggers.forEach(item => { // 生成相应的事件处理器,并在其中做输入校验。 eventHandlers[item] = e => { const { value } = e.target; setError(!validator(value)); }; }); return eventHandlers; } const eventHandlers = createEventHandlers(); return { value, helperText, error, ...eventHandlers, onChange, };}
新闻热点
疑难解答
图片精选