開始之前
閱讀本文需要對以下幾項有一定了解
ECMAScript 6
文章中大量用到了 ES6 語法,比如解構(gòu)賦值和函數(shù)參數(shù)默認(rèn)值、剩余參數(shù)、展開語法、箭頭函數(shù)等。
Hooks
React 在 16.8 版本中推出了 Hooks,它允許你在“函數(shù)組件”中使用“類組件”的一些特性。
React 本身提供了一些 Hooks,比如 useState、useReducer 等。通過在一個以“use”作為命名起始的函數(shù)中調(diào)用這些 Hooks,就得到了一個 custom Hook(自定義 Hook)。
Custom Hooks 允許我們把任何邏輯封裝到其中,以便于復(fù)用足夠小的組件邏輯。
Controlled Components
當(dāng)我們把像 <input> <textarea> 和 <select> 這樣的 HTML 元素本身的狀態(tài)交給 React state 去管理,我們就得到了一個“受控組件”。
styled-components
一個與 React 契合良好的 CSS in JS 庫。它允許你使用 JS 編寫樣式,并編譯成純 CSS 文件。
下面代碼中所有的樣式都是使用它編寫的。如果對代碼中樣式的實現(xiàn)不是很感興趣的話, 這個可以跳過。
代碼實現(xiàn)
Input 組件
首先我們需要實現(xiàn)一個 Input 組件,我們將在該組件的基礎(chǔ)上進(jìn)行輸入、校驗并提示。
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 標(biāo)簽的文本 type 賦值給原生 input 標(biāo)簽的 type 屬性 error 數(shù)據(jù)類型為 Boolean,如果為 true 則表示當(dāng)前表單域有錯誤,即驗證不通過 helperText 當(dāng)前表單域驗證不通過時,顯示在表單域下方的提示文字 otherProps props 中除了上述四個以外的其他屬性,全部賦值給原生 input 標(biāo)簽Custom Hook
有了 UI 組件之后,就可以開始實現(xiàn)我們的自定義 Hook 了。
useInput.js
import { useState } from 'react';export default function useInput({ initValue = '', helperText = '', validator = () => true, validateTriggers = ['onChange'],} = {}) { // 保存用戶輸入的值,使用 initValue 作為初始值 const [value, setValue] = useState(initValue); // Boolean 類型,表示當(dāng)前表單項的驗證狀態(tài) const [error, setError] = useState(false); function onChange(e) { const { value } = e.target; setValue(value); // 根據(jù) validateTriggers 的選項,決定是否要在 onChange 里進(jìn)行校驗 if (validateTriggers.includes('onChange')) { setError(!validator(value)); } } /** * 根據(jù) validateTriggers 生成相應(yīng)的事件處理器 */ function createEventHandlers() { const eventHandlers = {}; validateTriggers.forEach(item => { // 生成相應(yīng)的事件處理器,并在其中做輸入校驗。 eventHandlers[item] = e => { const { value } = e.target; setError(!validator(value)); }; }); return eventHandlers; } const eventHandlers = createEventHandlers(); return { value, helperText, error, ...eventHandlers, onChange, };}
新聞熱點
疑難解答
圖片精選