上篇文章说到,context
上下文一般用于第3方组件库,因为使用场景是需要多个组件之间相互配合实现一整套的逻辑。(高内聚的思想)
所以利用上下文的特性简单封装一个表单,看看如何实现和使用。
在 element-ui 中 Form 表单组件之间的联动,也是一个思想。它使用的 发布订阅模式 来逐层传递数据。
整体目录:
src/components/Form
-- index.js
-- context.js // 存放上下文数据。
-- FormInput.js
-- FormButton.js
import React, { Component } from "react";
import PropTypes from "prop-types"; // 用于验证 props 类型
import { Provider } from "./context";
import FormInput from "./FormInput";
import FormButton from "./FormButton";
export default class Form extends Component {
state = {
formData: {},
changeFormData: (name, value) => {
this.setState({
formData: {
...this.state.formData,
[name]: value,
},
});
},
submit: () => {
this.props.onSubmit?.(this.state.formData);
},
};
static propTypes = {
onSubmit: PropTypes.func,
};
render() {
return <Provider value={this.state}>{this.props.children}</Provider>;
}
}
// 赋值到 Form 组件上方便引用。
Form.Input = FormInput;
Form.Button = FormButton;
import React from "react";
const ctx = React.createContext();
export const { Provider, Consumer } = ctx;
export default ctx;
注意 input.value
属性,因为 this.context.formData[this.props.name]
一开始是 undefined
,所以得加一个默认值 ''
,否则 React 会认为是非受控组件而报错。
import React, { Component } from "react";
import PropTypes from "prop-types";
import ctx from "./context";
export default class FormInput extends Component {
static contextType = ctx;
static defaultProps = {
type: "text",
};
static propTypes = {
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
};
render() {
return (
<div>
<input
type={this.props.type}
name={this.props.name}
value={this.context.formData[this.props.name] || ""}
onChange={(e) => {
this.context.changeFormData(this.props.name, e.target.value);
}}
></input>
</div>
);
}
}
import React from "react";
import { Consumer } from "./context.js";
export default function FormButton(props) {
return (
<Consumer>
{(ctx) => {
return <button onClick={() => ctx.submit()}>{props.children}</button>;
}}
</Consumer>
);
}
import React, { Component } from "react";
import Form from "./components/Form/index";
export default class App extends Component {
render() {
return (
<div>
<Form
onSubmit={(formData) => {
console.log(formData);
}}
>
<div>
<label>用户名</label>
<Form.Input name="id"></Form.Input>
</div>
<div>
<label>用户名</label>
<Form.Input name="pwd" type="password"></Form.Input>
</div>
<Form.Button>获取FormData</Form.Button>
</Form>
</div>
);
}
}
最终,点击按钮就能获取到 formData
更新后的数据。
以上。