爲何叫 Den Form ? 多是由於
丹鳳眼
很是迷人吧...css
一個很是輕巧的 Form 實現, gzip 體積只有 3kb, 能夠很方便跨越組件層級獲取表單對象, 或者管理聯動更新react
$ yarn add react-den-form
複製代碼
Form 組件會在有 field 屬性的子組件上注入 onChange 事件, 並獲取其中的值json
field 屬性是 Form 組件用於標記哪一類子組件須要被監管的字段, 而且也是用於校驗更新的 keyapi
field 能夠重複, 可是若是兩個子組件擁有相同的 field 值, 那麼當此類 field 須要更新時, 兩個子組件都會進行更新bash
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div> <Form onSubmit={({ data }) => console.log(data)}> <input field="userName" /> </Form> </div> ); }; 複製代碼
當咱們輸入數據後, 按回車鍵, onSubmit 方法打印以下:app
{userName: "333"}
複製代碼
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div>
<Form onChange={({ data }) => console.log(data)}>
<div>
<div>
<div>
<input field="userName" />
</div>
<input field="password" />
</div>
</div>
</Form>
</div>
);
};
複製代碼
當咱們輸入數據時, onChange 方法打印以下:異步
{userName: "333", password: "555"}
複製代碼
有時候, 咱們會有一些頁面結構讓兩個不一樣的表單進行嵌套, 如登陸時, 驗證碼的輸入框在用戶名和密碼中間, 而驗證碼有單獨的請求. 固然, 咱們能夠更換實現方式, 可是對於這類場景, DenForm 默認處理了表單嵌套.ide
因爲 Form 內部有一個 form 標籤, 外層 onSubmit 會捕獲全部子組件的 onSubmit 事件, 可是 data 數據只會捕獲 當前層級內的 field 對象函數
export default () => {
return (
<div>
{/* 此 Form 只會捕獲 userName及password, code被子Form攔截了 */}
<Form onSubmit={({ data }) => console.log("1", data)}>
<input field="userName" />
{/* 此 Form 只會捕獲 age */}
<Form onSubmit={({ data }) => console.log("2", data)}>
<input field="code" />
<button type="submit">此Submit會被最近的父級捕獲</button>
</Form>
<input field="password" />
</Form>
</div>
);
};
複製代碼
import React from "react";
import Form from "react-den-form";
// 此對象會被注入 ToForm 組件
function SubInput({ ToForm }) {
return (
<div>
<div>
<ToForm>
<input field="subPassword" />
</ToForm>
</div>
</div>
);
}
export default () => {
return (
<div>
<Form onChange={({ data }) => console.log(data)}>
<div>
<div>
<div>
<input field="userName" />
</div>
<input field="password" />
<SubInput toform />
</div>
</div>
</Form>
</div>
);
};
複製代碼
當咱們輸入數據時, onChange 方法打印以下:post
{userName: "333", password: "555", subPassword: "666"}
複製代碼
若是咱們本身定義的特殊組件, 須要知足兩個條件:
import React from "react";
import Form from "react-den-form";
class SubInput extends React.Component {
handleOnChange = e => {
// 須要使用 this.props.onChange 返回數據
this.props.onChange(e.target.value);
};
render() {
return <input onChange={this.handleOnChange} />;
}
}
export default () => {
return (
<div>
<Form onChange={({ data }) => console.log(data)}>
{/* 須要設置 field 屬性 */}
<SubInput field="userName" />
</Form>
</div>
);
};
複製代碼
如下標籤, From 會自動識別 onChange 的返回值, 進行解析獲取
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div>
<Form onChange={(...args) => console.log(args)}>
<input field="userName" />
<textarea field="password" />
<select field="loginType">
<option value="signUp">Sign up</option>
<option value="signIn">Sign in</option>
</select>
</Form>
</div>
);
};
複製代碼
咱們本身定義的特殊組件, 若是它們的 onChange 的返回值結構不肯定, 咱們能夠編寫 onChangeGetter 屬性:
import React from "react";
import Form from "react-den-form";
class SubInput extends React.Component {
// 假定數據有必定的層級
inputData = {
value: ""
};
handleOnChange = e => {
this.inputData.value = e.target.value;
this.props.onChange(this.inputData);
};
render() {
return <input onChange={this.handleOnChange} />;
}
}
export default () => {
return (
<div>
<Form onChange={({ data }) => console.log(data)}>
<SubInput field="userName" onChangeGetter={e => e.value} />
</Form>
</div>
);
};
複製代碼
onChangeGetter
的默認值至關於onChangeGetter={e => e}
如下三個情形爲都會觸發 Form 的 onSubmit 函數:
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div>
<Form onSubmit={({ data }) => console.log(data)}>
<input field="userName" />
<input submit field="password" />
<button type="submit" />
</Form>
</div>
);
};
複製代碼
Form 表單內部並沒有封裝請求行爲, 請在 onSubmit 事件中自行處理, 如:
import React from "react";
import Form from "react-den-form";
function fetchLogin({ data }) {
fetch("/api/login", { method: "post", body: JSON.stringify(data) })
.then(res => {
return res.json();
})
.then(data => {
console.log(data);
});
}
export default () => {
return (
<div>
<Form onSubmit={fetchLogin}>
<input field="userName" />
<input field="password" />
</Form>
</div>
);
};
複製代碼
咱們爲 Form 顯式注入一個 data, 當數據變化時, data 的值也會變化, 這樣能夠在上下文獲取 Form 的數據
// React.Component 版本
import React from "react";
import Form from "react-den-form";
export default class extends React.Component {
data = {};
render() {
return (
<div> <Form data={this.data}> <input field="userName" /> <button onClick={() => console.log(this.data)}>show-data</button> </Form> </div> ); } } 複製代碼
// useHooks 版本
import React, { useState } from "react";
import Form from "react-den-form";
export default () => {
const [data] = useState({});
return (
<div> <Form data={data}> <input field="userName" /> <button onClick={() => console.log(data)}>show-data</button> </Form> </div> ); }; 複製代碼
輸入數據, 點擊 button, data 數據打印以下:
{ userName: "dog" }
複製代碼
表單校驗是無痛的, 而且是高效的
咱們給 input 組件添加 errorcheck 屬性, 該屬性能夠是一個正則對象, 也能夠是一個 函數, 若是 errorcheck 校驗的結果爲 false
, 就會將其餘 error 相關的屬性賦予至組件中
以下代碼, 若是 input 內容不包含 123
, 字體顏色爲紅色:
import "./App.css";
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div> <Form> <input field="userName" errorcheck={/123/} errorstyle={{ color: "#f00" }} /> </Form> </div> ); }; 複製代碼
prop | 類型 | 用途 |
---|---|---|
errorcheck | 正則或函數 | 若返回值爲 false, 將其餘 error Api 應用至組件中 |
errorstyle | style 對象 | 若校驗爲錯誤, 將 errorstyle 合併至 style 中 |
errorclass | className 字符串 | 若校驗爲錯誤, 將 errorstyle 合併至 className 中 |
errorprops | props 對象 | 若校驗爲錯誤, 將 errorprops 合併至整個 props 中 |
爲何是 errorcheck 而不是 errorCheck ? 這是由於 React 對 DOM 元素屬性的定義爲 lowercass:
Warning: React does not recognize the `errorCheck` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `errorcheck` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
複製代碼
若是咱們有一個需求, 當表單校驗錯誤時, 顯示一個提示信息, 當表單校驗經過時, 取消提示信息, 咱們就須要對每次校驗有差別時, 進行處理
使用 onChange 方法每次都會被執行, 但是咱們只但願在表單校驗結果有變化時進行提示
Form 提供了一個 onErrorCheck 的屬性, 知足以上需求
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div> {/* 只有當 input內容校驗結果發生變化時, onErrorCheck 纔會執行 */} <Form onErrorCheck={({ isError, data }) => console.log(isError, data)}> <input field="userName" errorcheck={/123/} errorstyle={{ color: "#f00" }} /> </Form> </div> ); }; 複製代碼
當咱們修改一個對象時, 根據某些條件, 但願修改另外一個對象的行爲咱們稱之爲聯動
DenForm 的聯動是高性能的, 僅更新須要更新的對象
咱們能夠在任何 Form 的回調函數中使用 update 進行更新某個被 field 捆綁的組件的 value 或者 props
下面這個例子: 1. 當在 password 輸入時, 會將 userName 的 input 框內容改成 'new value'; 2. 當 userName 的 input 的內容包含 'aa' 時, 會將 password 的 value 和 style 進行修改;
import React from "react";
import Form from "react-den-form";
export default () => {
return (
<div>
<Form
onChange={({ data, field, update }) => {
if (field === "password") {
update({ userName: "new value" });
}
if (/aa/.test(data.userName)) {
update({
password: {
value: "new value and style",
style: { fontSize: 30 }
}
});
}
}}
>
<input field="userName" />
<input field="password" />
</Form>
</div>
);
};
複製代碼
Form 存在的意義在於簡化開發, 用計算機的時間換取開發者的時間, 因此會有一些性能開銷.
可是 Form 的開銷絕對不大, 由於 Form 內部更新時只會針對指定的子組件進行更新.
<Form shouldUpdate={false} >{...}</Form>
若是由於使用 Form 遇到了性能問題, 請檢查如下狀況:
<Form shouldUpdate={false} >{...}</Form>
咱們有理由相信, 在一個設計合理的應用中, 每一個 Form 包裹的組件個數應該是有限的
此庫支持全部 React 的渲染層, 如 ReactDOM, ReactNative, ReactVR, 可是非 ReactDOM 中, 須要初始化事件類型
如 ReactNative 中, 在項目之初設定:
import { immitProps } from "react-den-form";
// 設定 ReactNative 中的讀取值和更新值的監聽屬性:
immitProps.value = "value";
immitProps.change = "onChange";
immitProps.click = "onPress";
複製代碼
屬性 | 描述 | 類型 | 默認值 | 必填 |
---|---|---|---|---|
data | 用於捆綁上下文的 data 對象, 也會當成默認值設置到相應的 field 監管的組件中 | Object: {:} | {} | -- |
onChange | 當有 field 監管的子組件執行 onChange 時, 進行回調 | (IEvents) => void | undefined | -- |
onSubmit | 當有表單進行提交時, 進行回調 | (IEvents) => void | undefined | -- |
onErrorCheck | 當有 field 監管的子組件的錯誤校驗結果發生變化時, 進行回調 | (IEvents) => void | undefined | -- |
Form 組件回調函數的參數以下: ({isError, event, data, field, value, element, update }) => void
具體的 API 描述以下:
屬性 | 描述 | 類型 | 默認值 | 必傳 |
---|---|---|---|---|
isError | 最後輸入的對象校驗是否正確 | Boolean | false | true |
event | onChange 的原始返回對象 | Boolean | undefined | false |
data | form.data 對象, 包含全部 field 監管的值 | Object: {:} | {} | true |
field | 當前修改的組件的 field 屬性 | String | undefined | true |
value | 當前修改的值 | Boolean | '' | String or Number |
element | 當前修改的 ReactElement | Boolean | React.Element | true |
update | 更新某個 field 監管的對象 | (IEvents)=> {:} | (IEvents)=> {:} | true |
一個子組件能夠被識別關聯的參數以下
<input
field="userName"
submit
type="submit"
errorcheck={/123/}
errorstyle={{ color: "#f00" }}
errorclass="input-error-style"
errorprops={{ disable: true }}
/>
複製代碼
具體的 API 描述以下:
屬性 | 描述 | 類型 | 默認值 | 必傳 |
---|---|---|---|---|
field | 用於標記組件是否被 Form 組件監聽, 而且也是 data 用於存放值的 key | String | undefined | |
submit | 用於肯定當前對象是否能夠響應 onClick 事件進行提交 | Boolean | undefined | -- |
toform | 注入ToForm 組件, 讓子組件對象也能夠歸納子表單 | Boolean | undefined | |
type | 當 type = "submit" 時, 能夠響應 onClick 事件進行提交 | Object: {:} | undefined | -- |
errorcheck | 用於校驗當前對象 value 是否錯誤 | 正則對象或函數 | undefined | -- |
errorstyle | 當前對象 value 錯誤時, 合併 errorstyle 至 style | Object | undefined | -- |
errorclass | 當前對象 value 錯誤時, 合併 errorclass 至 className | String | undefined | -- |
errorprops | 當前對象 value 錯誤時, 合併 errorprops 至 props | Object | undefined | -- |
以上就是所有, 但願 Den Form 可以幫到你解決 React 表單相關的痛點 :)