這篇文章要跟大家分享的內容是關於Pastate.js 響應式react 框架之表單渲染與操作 ,有著一定的參考價值,有需要的朋友可以參考一下
這是Pastate.js響應式react state 管理框架系列教學的第四章,歡迎關注,並持續更新。 Pastate.js Github
這一章,讓我們來看看如何在 pastate 裡渲染和操作表單元素。
我們在 BasicInfoView
元件的兩個按鈕下方新增一個輸入方塊用於輸入姓名,並新增一個勾選方塊用於選擇性別,更改如下:
class BasicInfoView extends PureComponent { render() { ... return ( <p style={{ padding: 10, margin: 10 }}> ... <p> <button onClick={this.decreaseAge}> decrease age </button> <button onClick={this.increaseAge}> increase age </button> </p> <p> name: <input type="text" value={state.name} onChange={this.handleNameChange}/> <br /> Is boy: <input type="checkbox" checked={state.isBoy == true} onChange={this.handleIsBoyChange}/> </p> </p> ) } }
上面新增兩個了input 標籤,第一個input 使用name 資料, 第二個input 使用isBoy 資料。同時我們也先指定兩個 input 的 onChange 處理函數。
注意:如前面章節所提及,對於 imState 布林值,請記得使用明確布林值方式:checked={state.isBoy == true}
。
接下來看看如何實作兩個 onChange 處理函數:
class BasicInfoView extends PureComponent { ... handleNameChange(e){ state.basicInfo.name = e.target.value store.sync() // 编辑中的输入框,需手动同步store } handleIsBoyChange(e){ state.basicInfo.isBoy = e.target.checked } ... }
非常熟悉且簡單!你只要把更新的值賦給目標state節點。我們會發現多了一個 store.sync()
,這個函數就是讓 pastate 立刻執行資料同步更新。由於許多輸入法會在輸入過程中會把帶下劃線的「拼音字母」 輸入到input 中,如下:
##如果pastate 執行非同步更新會使下劃線「拼音字母」 中斷,因此我們在更新
編輯中的輸入框 時,需要簡單地使用 store.sync() 執行同步更新,讓「拼音” 連續。如果不是對
編輯中的輸入框 進行修改或不需要支援輸入法輸入(如密碼等),則無需使用 store.sync() 。
class BasicInfoView extends PureComponent { ... // 把输入值都转化为大写 handleNameChange_uppercase(e){ state.basicInfo.name = e.target.value.toUpperCase() store.sync() } // 控制文本长度在10个字符以内 handleNameChange_limitedLength(e){ if(e.target.value.length > 10) return; state.basicInfo.name = e.target.value store.sync() } ... }使用pastate 雙向綁定輸入元件使用過vue.js 或angular.js 的人都體驗過自動雙向資料綁定(two-ways data binding) 的便捷性,但由於react state 渲染的單向資料流原則,在react 中沒有預設提供這個功能。而 pastate 的 imState 具有保存節點資訊的特殊性,能夠輕鬆實現自動雙向資料綁定功能! pastate 為你提供了四個已實現雙向資料綁定的高階表單元件(Higher Order Component, 通常簡稱HOC) ,這些元件都是基於PureComponent 實現的,具有良好的渲染性能,你可以盡情享用他們!這四個表單元件如下:
Input : 文字方塊
: 複選框
: 單選框選項組
: 下拉選擇框
import { ..., Input } from 'pastate' ... render(){ let state = this.props.state return( ... <Input value={state.text1} /> {/** 单行输入框,内部使用 <input type="text" /> 实现 */} <Input value={state.text2} type="textarea" /> {/** 多行输入框,内部使用 <textarea /> 实现 */} ... ) } ...
Input 元件的屬性及其說明如下:
屬性| 值| 說明
value | boolean,必填 | 绑定的数据值,可直接传入 this.props.state 中的节点值,无需做 state.xxx == true
转化。
afterChange | (newValue: boolean) => void | 在绑定值更新后会被调用
disabled | boolean | 指定禁止点击状态,默认为 false
className | string | 传递 class 名 ( 用于指定 css 样式等 )
id | string | 传递 id 名 ( 用于指定 css 样式等 )
RadioGroup 是一个单选框选项组,只要传入选项数组 options 常数和要绑定的选项值 value, 即可完成绑定:
import { ..., RadioGroup } from 'pastate' const goodNames = ['Peter', 'Tom', 'Allen'] ... render(){ let state = this.props.state return( ... Choose a name: <RadioGroup options={goodNames} value={state.name}/> ... ) } ...
RadioGroup 组件的属性及其说明如下:
属性 | 值 | 说明
options | Arrayb3642d4c1bbe188f2264a1d93e963eb8 | Arrayc20d85f48d46354c5561c6166559a7cc, 必填 | 选项数据数组
value | string | number | boolean,必填 | 绑定的选中值
disabled | boolean | 指定禁止选择状态,默认为 false
vertical | boolean | 指定选项为垂直排列状态,默认为 false
afterChange | (newValue: string | number | boolean) => void | 在绑定值更新后会被调用
id | string | 传递给选项组根元素的 id
className | string | 传递给选项组根元素的 className
radioClassName | string | 传递给圆形按钮的 className
tagClassName | string | 传递给选项标签的 className
disabledTagClassName | string | 传递给禁用状态的选项标签的附加的 className
options 属性接受两种格式的选项数据格式:
// 简单格式: Array<string> const nameOptions = ['Peter', 'Tom', 'Allen'] // 完备格式: Array<{value: string, tag: string, disabled?: boolean}> const nameOptionsChinese = [{ value: 'Peter', // 数据值 tag: '彼得', // 选项标签值 disabled: true // 可选地指定某个选项为不可选 },{ value: 'Tom', tag: '汤姆' },{ value: 'Allen', tag: '艾伦' }]
RadioGroup
是基于 PureComponent 实现的,对于 options 属性的值,建议定义一个 文件级 的选项数组常量, 这样可以提高渲染效率。如果把 options 值定义在 render 函数里或写成直接赋值的匿名对象(5196972e5a78b4540509c19f0f6fa6ba
), 在每次父组件渲染时,无论绑定的 value 数据有没有更新,RadioGroup 获取到的 options 属性的引用值都不一样,会使 RadioGroup 进行多余的渲染动作。 当你使用其他基于 PureComponent 实现的组件时,在向其传递数组 / 对象类型的常量的时候也可以做这样的性能优化。
Select 是一个选择框组件,使用方法与 RadioGroup 类似,只要传入选项数组和要绑定的选择值即可完成绑定:
import { ..., Select } from 'pastate' const nameOptionsChinese = [{ value: 'DEFAULT', tag: '请选择', disabled: true },{ value: 'Peter', tag: '彼得' }, { value: 'Tom', tag: '汤姆' }, { value: 'Allen', tag: '艾伦' }] ... render(){ let state = this.props.state return( ... Choose a name: <Select options={nameOptionsChinese} value={state.name}/> ... ) } ...
Seclect 组件的属性及其说明如下:
属性 | 值 | 说明
options | Arrayc75eec7597418609098cc9cfad3bb2a5 | Arrayab7dfcd85a89b209aac5f66d4698aea9, 必填 | 选项数据数组
value | string | number | boolean,必填 | 绑定的选中值
disabled | boolean | 指定禁止点击状态,默认为 false
afterChange | (newValue: string | number | boolean) => void | 在绑定值更新后会被调用
id | string | 传递的 id
className | string | 传递的 className
如有需要显示没有选择的状态,可以多设置一个选项元素,通过元素的 tag 设置其提示文本, 并把元素的 disabled 设为 true 即可,没选中时的 value 值自行定义,不可为 null 或 undefined:
const nameOptionsChinese = [{ value: 'DEFAULT', tag: '请选择', disabled: true }, ... ]
Seclect 组件目前仅支持最常用的单选功能,以后将支持多选功能。
Pastate 的高阶组件均是使用 Typescript 进行开发 , 提供完整的类型定义文件,当你在 javascript 项目使用它们时,也可以得到良好的组件属性 intelliSense 类型提示:
你也可以右键点击组件名,选择转到类型定义
, 查看组件的所有属性声明:
上图的 type 属性的类型是枚举字符串,在输入时,你可以在空双括号中按下 vsCode 的 “触发提示” 快捷键(具体快捷键因不同系统操作系统和不同设置而异,请到编辑器的 “首选项->设置快捷方式” 处查看,该功能很实用):
很多时候,我们会使用 react 视图组件库来开发应用,如 ant.design、 material-ui 等,pastate 为这些现有的视图组件提供两个数据双向绑定方法!下面我们以 ant.design 的 Rate 星级评分组件为例进行介绍。
你可以使用 pastate 提供的 Bind 组件去包围一个原始的视图组件,实现双向数据绑定。
我们先简单地安装 ant.design 组件库: $ npm install antd --save
或 $ yarn add antd
,引入 Rate 组件,并使用 Bind 组件进行包装,实现双向数据绑定:
import { ..., Bind } from 'pastate'; import Rate from 'antd/lib/rate'; import 'antd/lib/rate/style/css'; // 或经过简单配置后,使用 import { Rate } from 'antd', 详见 ant.design 文档 ... // 我们使用 state.basicInfo.age 数据进行演示 class BasicInfoView extends PureComponent { ... render() { /** @type {initState['basicInfo']} */ let state = this.props.state; return ( <p style={{ padding: 10, margin: 10 }}> ... <p> 年龄(Bind): <Bind value={state.age} > <Rate /> </Bind> </p> ... </p> ) } }
我们使用 Bind 组件对 Rate 组件进行包装,并把本来需要传递给 Rate 组件的 value 值传递通过 Bind 组件进行传递,这样就实现了双向数据绑定!如果我们要传递其他属性值给 Rate, 可以不通过 Bind 直接传递给 Rate,如下:
... <Bind value={state.age} > <Rate count={10} /> {/* 根据 ant design 文档, count 属性指定采用 n 级评分 */} </Bind> ...
这样我们就实现了对 Rate 进行双向数据绑定:
你可以通过点击 Rate 组件的星星或点击 descrease age
,increase age
按钮对年龄值进行改变,可以发现当通过按钮更新数据时,Rate 组件可以正确响应。而且 Bind 是一个关于 value 的纯组件,当其他无关数据发生改变时,Bind 元素不会发生多余的渲染动作。
Bind 元素还有两个可选的属性:
valueProp: 指定被包装的组件接收数据的属性名,默认是 value
, 绝大多数组件也是用 value
,因此无需指定该值。如果被包装的组件使用的是 checked
或其他属性名接收数据值,那么请把 Bind 元素的 valueProp 设为对应的 checked
或其他属性名。
afterChange: 当组件绑定的值通过该组件发生改变后,会调用该函数,该函数的签名为 (newValue) => void
。当绑定的属性值不是通过该组件发生改变时,afterChange 函数不会被调用。
你也可以使用 makeBindable(RawComponent, valueProp = 'value')
函数生成一个可以复用的可绑定组件:
import { ..., makeBindable } from 'pastate'; ... // 使用 makeBindable 生成对应的可以绑定数据的 Rate 组件 const MyRate = makeBindable(Rate) class BasicInfoView extends PureComponent { ... render() { /** @type {initState['basicInfo']} */ let state = this.props.state; return ( <p style={{ padding: 10, margin: 10 }}> ... <p> 年龄(makeBindable): <MyRate count={10} value={state.age}/> </p> ... </p> ) } }
你可以通过 makeBindable 函数的第二个参数指定 valueProp 值,如 const MyCheckbox = makeBindable(Checkbox, 'checked')
, 同样,你可以通过新组件的 afterChange 属性去响应组件值更新后的个性化操作。
无论使用 pastate 的表单输入组件还是包装现有的组件库,对于组件绑定的数据值,不支持被设为 null 值 或 undefind 值。通常情况下,我们不会有这种需求。如果需要实现表单的“未选择”状态, 我们一般通过设置一个默认值且不可选的 default 值来代替。例如有个表单需要选择性别,并且需要一个未选择的状态,这样使用一个 RadioGroup 组件来实现:
let initState = { sex: '' // 用字符串表示性别,并设置为选择状态是的值为空字符串 '' 或 'default' } const sexOptions = ['boy', 'girl'] // 只包含目标值 ... render(){ let state = this.props.state; return <RadioGroup options={sexOptions} value={state.sex} /> } ...
如果你的需求场景一定要用到 null 或 undefined 值,欢迎在 issues 中分享。 Pastate 能实现绑定的值支持空值,但如果这个需求只有在非常特殊的情况下才用到,我们就暂不把它默认实现在 pastate 库中,因为这会增加计算量,你可以自行实现这个特殊组件的数据绑定逻辑。
下一章,我们来看看 pastate 应用如何进行模块化。
相关推荐:
以上是Pastate.js 響應式 react 框架之表單渲染與操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!