The content shared with you in this article is about the form rendering and operation of the Pastate.js responsive react framework. It has a certain reference value. Friends in need can refer to it.
This is Pastate.js Chapter 4 of the series of tutorials on responsive react state management framework. Welcome to pay attention and continue to update. Pastate.js Github
In this chapter, let’s take a look at how to render and operate form elements in pastate.
We add an input box under the two buttons of the BasicInfoView
component to enter the name, and add a check box to select the gender , the changes are as follows:
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> ) } }
Two input tags are added above, the first input uses name data, and the second input uses isBoy data. At the same time, we also specify the onChange handler functions of the two inputs first.
Note: As mentioned in the previous chapter, for imState Boolean values, please remember to use the explicit Boolean value method: checked={state.isBoy == true}
.
Next let’s see how to implement two onChange handler functions:
class BasicInfoView extends PureComponent { ... handleNameChange(e){ state.basicInfo.name = e.target.value store.sync() // 编辑中的输入框,需手动同步store } handleIsBoyChange(e){ state.basicInfo.isBoy = e.target.checked } ... }
Very familiar and simple! You only need to assign the updated value to the target state node. We will find that there is an additional store.sync()
. This function allows paste to perform data synchronization updates immediately. Because many input methods will input underlined "Pinyin letters" into the input during the input process, as follows:
If pastate executes asynchronously The update will interrupt the underlined "Pinyin letters", so when we update the input box in editing, we need to simply use store.sync()
to perform a synchronous update so that "Pinyin ” Continuously. If you are not modifying the input box in editing or do not need to support input method input (such as passwords, etc.), there is no need to use store.sync()
.
Initially completed! We try to enter text into the input box, or click on the check box, and we can see that the value of the text area and the view of the input area are updated normally!
The same as the processing mode of ordinary react forms, we can control the input content in real time through the onChange function, such as converting upper and lower case, controlling the string length, etc.:
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() } ... }
Anyone who has used vue.js or angular.js has experienced the convenience of automatic two-way data binding (two-ways data binding), but due to the one-way data flow principle of react state rendering, This feature is not provided by default in react. The imState of paste has the particularity of saving node information, and can easily implement the automatic two-way data binding function!
pastate provides you with four higher-order form components (Higher Order Component, usually referred to as HOC) that have implemented two-way data binding. These components are all implemented based on PureComponent and have good rendering performance. You Feel free to enjoy them! The four form components are as follows:
Input
: Text box
Checkbox
: Complex Selection box
RadioGroup
: Radio button option group
##Select: Drop-down selection box
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 /> 实现 */} ... ) } ...
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 | Array
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 函数里或写成直接赋值的匿名对象(<RadioGroup options={["a", "b"]} ... >
), 在每次父组件渲染时,无论绑定的 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 | Array
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 state 管理框架
The above is the detailed content of Pastate.js responsive react framework form rendering and operation. For more information, please follow other related articles on the PHP Chinese website!