From 4f8d95f32256b65537fce65311f7cb6b697f57b2 Mon Sep 17 00:00:00 2001 From: ZiuChen Date: Fri, 21 Apr 2023 23:53:36 +0800 Subject: [PATCH] docs: React note update --- docs/note/React.md | 423 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 420 insertions(+), 3 deletions(-) diff --git a/docs/note/React.md b/docs/note/React.md index a647aef9..858a450f 100644 --- a/docs/note/React.md +++ b/docs/note/React.md @@ -144,7 +144,7 @@ root.render() - 当数据发生变化,可以调用 `this.setState` 来更新数据,通知React执行视图更新 - update操作时,会重新调用render函数,使用最新的数据来渲染界面 -:::success +::: tip 需要注意的是,在constructor中我们调用了`super`,因为App类是继承自React.Component类,调用`super`即调用了其父类的构造函数,让我们的App组件可以继承一些内置属性/方法如`state setState render` ::: @@ -2487,6 +2487,8 @@ const CustomInput = forwardRef((props, ref) => { 在React中,HTML表单的处理方式和普通DOM元素不太一样:表单通常会保存在一些内部的state中,并且根据用户的输入进行更新 +下例中创建了一个非受控组件,React只能被动从组件接受值并更新到state中,而无法主动更新组件的值 + ```tsx // Input.jsx import React, { PureComponent } from 'react' @@ -2517,11 +2519,426 @@ export default class Input extends PureComponent { } ``` +我们对例子稍加改动,将组件的`value`属性设置为state中的值,从而实现受控组件。 + +需要注意的是,绑定`value`属性的同时,我们也要绑定`onChange`事件,供用户输入时对state进行更新 + +```tsx {8,22} +// Input.jsx +import React, { PureComponent } from 'react' + +export default class Input extends PureComponent { + constructor(props) { + super(props) + this.state = { + value: 'default Value' + } + } + + handleInputChange = (ev) => { + this.setState({ + value: ev.target.value + }) + } + + render() { + return ( +
+

currentValue: {this.state.value}

+ +
+ ) + } +} +``` + +this.state.value默认值 => 渲染到Input标签内 => 用户输入 => 触发onChange事件 => 更新state => 渲染到Input标签内 => ... + +React要求我们要么指定`onChange`要么指定`readOnly`,只绑定`value`属性时,控制台会抛出错误 + +### 使用受控组件的几个例子 + +下例中分别使用`input`创建了几个受控组件,文本框、单选、多选 + +```tsx +import React, { PureComponent } from 'react' + +export default class Form extends PureComponent { + constructor(props) { + super(props) + this.state = { + username: 'ziu', + password: '123456', + isAgree: false, + hobbies: [ + { value: 'sing', label: 'Sing', isChecked: false }, + { value: 'dance', label: 'Dance', isChecked: false }, + { value: 'rap', label: 'Rap', isChecked: false }, + { value: 'music', label: 'Music', isChecked: false } + ], + fruits: ['orange'] + } + } + + handleInputChange = (ev, idx) => { + this.setState({ + [ev.target.name]: ev.target.value + }) + } + + handleAgreeChange = (ev) => { + this.setState({ + isAgree: ev.target.checked + }) + } + + handleHobbyChange = (ev, idx) => { + const hobbies = [...this.state.hobbies] // IMPORTANT + hobbies[idx].isChecked = ev.target.checked + this.setState({ + hobbies + }) + } + + handleSelectChange = (ev) => { + this.setState({ + fruits: [...ev.target.selectedOptions].map((opt) => opt.value) + }) + } + + handleSubmitClick = () => { + const { username, password, isAgree, hobbies, fruits } = this.state + console.log( + username, + password, + isAgree, + hobbies.filter((h) => h.isChecked).map((h) => h.value), + fruits + ) + } + + render() { + const { username, password, isAgree, hobbies, fruits } = this.state + return ( +
+ + +
+ +
+
+ Hobby: + {hobbies.map((hobby, idx) => ( + + ))} +
+
+ +
+
+ +
+
+ ) + } +} +``` + +这里有一点小知识,关于可迭代对象,可以通过`Array.from`将可迭代对象转为数组 + +方便我们使用数组的方法来操作选取的DOM列表 + +简单做一下总结,如何在React中绑定受控组件: + +| Element | Value Property | Change Callback | New Value in Callback | +| ------- | -------------- | --------------- | --------------------- | +| `` | value | onChange | event.target.value | +| `` | checked | onChange | event.target.checked | +| `` | checked | onChange | event.target.checked | +| `