为React组件编写API,第1部分:不要创建冲突的道具
编写用于React组件的API,第2部分:为行为命名,而非交互
为React组件编写API,第3部分:道具的顺序很重要
编写用于React组件的API,第4部分:当心提示!
编写用于React组件的API,第5部分:使用组合
我们为React组件编写API,第6部分:在组件之间创建通信
让我们谈谈形式。
您很可能以格式阅读了大量有关state
管理的文章,但这不是此类文章之一。 相反,我想谈谈表单及其API的工作方式。

这里有很多事情,看看API
<Form layout="label-on-left"> <Form.Field label="Name"> <TextInput type="text" placeholder="Enter your name" /> </Form.Field> <Form.Field label="Email"> <TextInput type="email" placeholder="email@domain.com" /> </Form.Field> </Form>
让我们看一下每个组件并进行分析:
所有这些都从Form
组件开始, Form
组件是带有附加类的基本表单元素。 它将呈现您放入其中的所有内容。
function Form(props) { return <form className="form">{props.children}</form> } render(<Form layout="label-on-left">...</Form>)
它还接受prop layout
,这在您空间较小时很有用。

<Form layout="label-on-top">...</Form>
这将更改标签对齐的方式(从右到左)以及margin
工作方式。
表单不控制其内部内容的宽度和margin
。 对于此表单中的输入字段,这已经是一个问题。
因此, Form
组件应在下面报告layout
信息。
最简单的方法是使用props传递layout
,但是表单的内容是动态的(由使用此表单的开发人员确定),我们不知道表单将是什么。
这是上下文API帮助我们的地方。
const LayoutContext = React.createContext() function Form(props) { return ( <form className="form"> <LayoutContext.Provider value={{ layout: props.layout }} > {props.children} </LayoutContext.Provider> </form> ) } export default Form export { LayoutContext }
现在,表单字段可以使用此上下文并获取layout
值
FormField
组件(表单输入字段)会将label
添加到您放置在其中的所有内容(例如,文本输入)。
function Field(props) { return ( <div className="form-field"> <label {...props}>{props.label}</label> {props.children} </div> ) }
除此之外,他还添加了一个用于layout
的类-来自我们在Form
组件中创建的上下文。
import { LayoutContext } from './form' function Field(props) { return ( <LayoutContext.Consumer> {context => ( <div className={`form-field ${context.layout}`}> <label {...props}>{props.label}</label> {props.children} </div> )} </LayoutContext.Consumer> ) }
React 16.8+ useContext钩子使语法更容易
import { LayoutContext } from './form' function Field(props) { const context = useContext(LayoutContext) return ( <div className={`form-field ${context.layout}`}> <label {...props}>{props.label}</label> {props.children} </div> ) }
如果您有兴趣,请参见以下CSS代码:
.form-field.label-on-left { max-width: 625px; display: flex; align-items: center; } .form-field.label-on-left label { text-align: right; width: 175px; margin-right: 25px; } .form-field.label-on-top { width: 100%; display: block; } .form-field.label-on-top label { text-align: left; margin-bottom: 25px; }
我要谈的最后一个细节是组件的这种奇怪的点分语法。
由于Field
(输入字段)始终与表单一起使用,因此将它们组合在一起是有意义的。
一种方法是从同一文件导出它:
import Field from './field' function Form(props) { } export default Form export { Field }
现在,用户可以将它们一起导入:
import Form, { Field } from 'components/form' render( <Form> <Field>...</Field> </Form> )
通过将Field
附加到表单的最基本部分,我们可以进行一些小的改进。
import Field from './field' function Form(props) { } Form.Field = Field export default Form
该代码之所以有效,是因为React组件是javascript对象,您可以向这些对象添加其他键。
对于用户而言,这意味着他在导入Form
时会自动收到一个Field
。
import Form from 'components/form' render( <Form> <Form.Field>...</Form.Field> </Form> )
我真的很喜欢这个API,它使Form
和Form.Field
之间的连接显而易见。
注意:您必须将上下文移动到另一个文件,以避免循环依赖。
句点和上下文的语法组合使我们的Form
组件更智能,同时保持了其对合成(复合)的可操作性。