Skip to content

Commit c856c39

Browse files
committed
feat[ptr]: 默认情况下,Form 对在里面的所有的 Input 都传递了 handleChange, 当其中一个变化时,直接修改了 Form 的 state, 那么整个 Form 、 Form 中所有的 Input 都会 re-rende
通过 useForm 内部管理的 _formValues 实现字段级别订阅更新、 _formState 表单整体状态的观察者模式
1 parent b56c210 commit c856c39

14 files changed

Lines changed: 11413 additions & 9932 deletions

File tree

Lines changed: 3 additions & 0 deletions
Loading

.effect-pictures/form-useForm.png

Lines changed: 3 additions & 0 deletions
Loading

React/sandboxs/package-lock.json

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

React/sandboxs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"react": "^16.8.6",
77
"react-dom": "^16.8.6",
8+
"react-hook-form": "^7.71.1",
89
"react-scripts": "3.0.1"
910
},
1011
"scripts": {

React/sandboxs/src/App.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React from 'react';
33

44
// import CoverButton from './test/CoverButton';
55
import Father from './test/Father';
6+
import Form from './components/Form';
67

78
const el = (
89
// 写在 组件中间{ }中的 会自动传入到 props.children
@@ -13,7 +14,8 @@ const el = (
1314
// }}
1415
// </CoverButton>
1516

16-
<Father />
17+
// <Father />
18+
<Form legend={['name','key']}/>
1719
)
1820

1921

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React from 'react';
2+
import { useController, useForm } from 'react-hook-form';
3+
import Input from '../Input';
4+
5+
function getFieldName(index) {
6+
return `field_${index}`;
7+
}
8+
9+
const FormField = React.memo(function FormField({ control, name, legend }) {
10+
const { field } = useController({
11+
name,
12+
control,
13+
defaultValue: ''
14+
});
15+
16+
return (
17+
<Input
18+
legend={legend}
19+
value={field.value}
20+
transform={field.onChange}
21+
/>
22+
);
23+
});
24+
25+
function Form({ legend }) {
26+
const legendList = React.useMemo(() => {
27+
return legend && legend.length ? legend : ['用户名'];
28+
}, [legend]);
29+
30+
const defaultValues = React.useMemo(() => {
31+
return legendList.reduce((result, _item, index) => {
32+
result[getFieldName(index)] = '';
33+
return result;
34+
}, {});
35+
}, [legendList]);
36+
37+
const { control, handleSubmit, reset } = useForm({
38+
defaultValues
39+
});
40+
41+
React.useEffect(() => {
42+
reset(defaultValues);
43+
}, [defaultValues, reset]);
44+
45+
const onSubmit = React.useCallback(
46+
(formValues) => {
47+
const values = legendList.map((_, index) => formValues[getFieldName(index)]);
48+
console.log(`你要提交的内容为:${values}`);
49+
},
50+
[legendList]
51+
);
52+
53+
return (
54+
<form onSubmit={handleSubmit(onSubmit)}>
55+
{legendList.map((item, index) => (
56+
<FormField
57+
key={`${item}-${index}`}
58+
control={control}
59+
legend={item}
60+
name={getFieldName(index)}
61+
/>
62+
))}
63+
<button type="submit">submit</button>
64+
</form>
65+
);
66+
}
67+
68+
export default Form;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import Input from '../Input';
3+
4+
export default class Form extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
8+
const legend = props.legend && props.legend.length ? props.legend : ['用户名'];
9+
10+
this.state = {
11+
legend,
12+
values: legend.map(() => '')
13+
};
14+
}
15+
16+
// Form 对在里面的所有的 Input 都传递了 handleChange
17+
// 当其中一个变化时,直接修改了 Form 的 state
18+
// 那么整个 Form 、 Form 中所有的 Input 都会 re-render
19+
handleChange = (index, nextValue) => {
20+
this.setState((prevState) => {
21+
const values = [...prevState.values];
22+
values[index] = nextValue;
23+
24+
return { values };
25+
});
26+
};
27+
28+
handleClick = () => {
29+
// 提交整个表单
30+
console.log(`你要提交的内容为:${this.state.values}`);
31+
}
32+
33+
render() {
34+
const { legend, values } = this.state;
35+
36+
return (
37+
<form>
38+
{legend.map((item, index) => (
39+
<Input
40+
key={`${item}-${index}`}
41+
legend={item}
42+
value={values[index]}
43+
transform={(nextValue) => this.handleChange(index, nextValue)}
44+
/>
45+
))}
46+
<button onClick={this.handleClick}>submmit</button>
47+
</form>
48+
);
49+
}
50+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react';
2+
3+
function Input(props) {
4+
console.log(`=== ${props.legend} render`)
5+
6+
function handleChange(e) {
7+
// 在子组件中将用户数据的值,传递给父组件
8+
// 让父组件来进行修改,那么就需要调用父组件传入的更新函数(事件)
9+
props.transform(e.target.value);
10+
}
11+
12+
return (
13+
<fieldset>
14+
<legend>{props.legend}</legend>
15+
{/* 受控组价 */}
16+
<input value={props.value}
17+
type="text" onChange={handleChange} />
18+
</fieldset>
19+
);
20+
}
21+
22+
export default Input;
File renamed without changes.

0 commit comments

Comments
 (0)