React.js -- 优化你的表单
React Form在构建 web 应用的时候,为了采集用户输入,表单变成了我们不可或缺的东西。大型项目中,如果没有对表单进行很好的抽象和封装,随着表单复杂度和数量的增加,处理表单将会变成一件令人头疼的事情。在 react 里面处理表单,一开始也并不容易。所以在这篇文章中,我们会介绍一些简单的实践,让你能够在 react 里面更加轻松的使用表单。如果你对 HTML 表单的基础掌握得不是太好,那么我建议你先阅读我的上一篇文章 深入理解 HTML 表单 好了,废话不多说,让我们先来看一个简单的例子。 示例LoginForm.js handleChange = evt => { this.setState({ username: evt.target.value,}); }; render() { return ( <form> <label> username: <input type="text" name="username" value={this.state.username} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); } 在上面的例子中,我们创建了一个输入框,期望用户在点击 submit 之后,提交用户输入。
数据的抽象对于每一个表单元素来说,除开 DOM 结构的不一样,初始值,错误信息,是否被 touched,是否 valid,这些数据都是必不可少的。所以,我们可以抽象一个中间组件,将这些数据统一管理起来,并且适应不同的表单元素。这样 Field 组件 就应运而生了。 Field 作为一个中间层,包含表单元素的各种抽象。最基本的就是 Field 的名字 和 对应的值。 Field: { name: String,// filed name,相当于上面提到的 key value: String,// filed value } 在实际情况中,还需要更多的数据来控制 Field 的表现行为,比如 Field:{ name: String,// filed value label: String,error: String,initialValue: String,valid: Boolean,invalid: Boolean,visited: Boolean,// focused touched: Boolean,// blurred active: Boolean,// focusing dirty: Boolean,// 跟初始值不相同 pristine: Boolean,// 跟初始值相同 component: Component|Function|String,// 表单元素 } 点这里了解 => Redux Form 对 Field 的抽象 UI的抽象Field 组件
Field.js static defaultProps = { component: Input,}; render() { const { component,noLabel,label,...otherProps } = this.props; return ( <label> {!noLabel && <span>{label}</span>} { createElement(component,{ ...otherProps }) } </label> ); }
Input 组件创建Input 组件的关键点在于使它变得“可控”,也就是说它并不维护内部状态。关于可控组件,接下来会介绍。 Input.js handleChange = evt => { this.props.onChange(evt.target.value); }; render() { return ( <input {...this.props} onChange={this.handleChange} /> ); } 看上面的代码,为什么不直接把 onChange 函数通过 props 传进来呢?就像下面这样 render() { return ( <input {...this.props} onChange={this.props.onChange} /> ); }
优化后的 LoginForm 如下: LoginForm.js class LoginForm extends Component { state = { username: '',}; handleChange = value => { this.setState({ username: value,}); }; render() { return ( <form onSubmit={this.handleSubmit}> <Field label="username" name="username" value={this.state.username} onChange={this.handleChange} /> <input type="submit" value="Submit" /> </form> ); } } 可控组件与不可控组件可控组件与不可控组件最大的区别就是:对内部状态的维护与否。 一个可控的 <input> 应该具有哪些特点?
<input type="text" value={this.props.username} onChange={this.handleChange} /> 点这里了解 => React 可控组件与不可控组件 使用 React 高阶组件进一步优化在 LoinForm.js 中可以看到,我们对 仔细观察上面的代码,不难发现,在每一次 onChange 事件中,都是通过一个 高阶组件在这里就不再展开了,我会在接下来的文章中专门来详细介绍这一部分内容。 withState.js const withState = (stateName,stateUpdateName,initialValue) => BaseComponent => class extends Component { state = { stateValue: initialValue,}; updateState = (stateValue) => { this.setState({ stateValue,}); }; render() { const { stateValue } = this.state; return createElement(BaseComponent,{ ...this.props,[stateName]: stateValue,[stateUpdateName]: this.updateState,}); } };
withHandlers.js const withHandlers = handlers => BaseComponent => class WithHandler extends Component { cachedHandlers = {}; handlers = mapValues( handlers,(createHandler,handlerName) => (...args) => { const cachedHandler = this.cachedHandlers[handlerName]; if (cachedHandler) { return cachedHandler(...args); } const handler = createHandler(this.props); this.cachedHandlers[handlerName] = handler; return handler(...args); } ); componentWillReceiveProps() { this.cachedHandlers = {}; } render() { return createElement(BaseComponent,{ ...this.props,...this.handlers,}); } }; 使用高阶组件改造后的 LoginForm 如下: LoginForm.js const withLoginForm = _.flowRight( withState('username','onChange',''),withHandlers({ onChange: props => value => { props.onChange(value); },onSubmit: props => event => { event.preventDefault(); console.log(props.username); },}) ); @withLoginForm class LoginForm extends Component { static propTypes = { username: PropTypes.string,onChange: PropTypes.func,onSubmit: PropTypes.func,}; render() { const { username,onChange,onSubmit } = this.props; return ( <form onSubmit={onSubmit}> <Field label="username" name="username" value={username} onChange={onChange} /> <input type="submit" value="Submit" /> </form> ); } }
点这里了解 => Recompose 结语对于复杂的项目来说,以上的抽象还远远不够,在下一篇文章中,会介绍如何进一步让你的 Form 变得更好用。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |