React 开发实战(一)- Repeat 组件
前言最近在写一个面向 React 初学者的系列教程玩转 React,内容对有 React 开发经验的同学来说可能太过于基础和啰嗦,不太感兴趣。所以我打算同时开始另外一个系列文章《React 开发实战》。该系列主要面向有 React 开发经验的同学,更侧重 React 实战,每一篇文章会跟大家一起开发一个 React 组件或者一个简单有趣的 React 应用,这些组件或者应用往往满足如下特点:
如果这些组件能直接应用到大家的实际开发中去,那再好不过了;如果不能,能给大家一点启发,我觉得这件事情也是很有价值的。 另外,每一篇文章后面都会附有本篇文章的完整示例和代码。 问题描述大家应该都见过这种应用场景,页面上的某一部分,需要能够让用户添加任意多项。 可能是表单中的一个字段,如下所示。
也可能是表单的一部分,如下所示,用户可以在一个表单内增加多个用户信息,然后将用户信息批量进行保存。
还有更变态的,如下所示,一个表单内用户信息部分可以添加多份,每一个用户信息中地址也可以添加多份。(Oh,My God. PM,你杀了我吧。)
还好,React 应付这种需求,还是小菜一碟。但是在一个 web 应用中有这么多的相似场景的话,如果我们挨个实现一遍,那真是太枯燥了,与搬砖无异。遇到这种情况,就需要我们把相同的功能抽象出来,做成组件,这将极大地提升你的开发效率。 基于这个场景,我们今天就开发一个能让其 children 重复任意多份的组件,我们就称之为 Repeat 吧。 你期望 Repeat 组件该怎么用在开发一个组件的时候,不要着急写代码,先想想你要把这个组件做成什么样子,例如这个 Repeat 组件,我希望有如下特性:
然后在代码中我期望可以这样来用 Repeat 这个组件: class App extends React.Component { handleChange(items) { console.info(items); } render() { <Repeat onChange={items => this.handleChange(items)}> <input type="text" /> </Repeat> } } OK,就是这么简单,这样 Input 组件就可以重复加添多份了。基于这个构想,我们来实现 Repeat 这个组件。 开始实现 Repeat 组件class Repeat extends React.Component { constructor(props) { super(props); this.state = { items: [''],}; } handleChange(e,index) { const items = [...this.state.items]; items[index] = e.target.value; this.setState({ items }); this.props.onChange(items); } handleAddItem(e,index) { e.preventDefault(); const items = [...this.state.items]; items.splice(index,''); this.setState({ items }); } handleRemoveItem(e,index) { e.preventDefault(); if (this.state.items.length === 1) return; const items = [...this.state.items]; items.splice(index,1); this.setState({ items }); } render() { const children = React.Children.only(this.props.children); const elementItems = this.state.items.map((item,index) => ( <div key={index}> { React.cloneElement(children,{ onChange: e => this.handleChange(e,index),value: item,}) } <div> <a href="#" onClick={e => this.handleAddItem(e,index)}>添加</a> <a href="#" onClick={e => this.handleRemoveItem(e,index)}>移除</a> </div> </div> )); return <div>{elementItems}</div>; } } 代码很简单,简单解释一下:
到此, 跟 children 有个约定有些同学可能已经发现了,上面例子中, 这是第一个问题,为了解决这个问题呢,Repeat 需要对它的
这就是一个协议,你希望某个组件内通过 其实在计算机的世界中处处充满了协议,例如你想让 HTTP Server 返回正确的响应,你必须要遵循 http 协议来和它通信;你生产的显卡能买的出去,必须要遵守相应的协议,要能插到别人家生产的主板上。 扯远了!收! 对,有了上面这个约定以后, 聪明的你一定已经知道该怎么做了,没错,只要我们实现一个 class UserForm extends React.Component { handleFieldChange(e) { const { name,value } = e.target; const formData = { ...this.props.value,[name]: value,} this.props.onChange({ target: { value: formData,} }); } render() { const formData = this.props.value || {}; return ( <div> <div> <label for="">姓名</label> <input type="text" name="name" value={formData.name} onChange={e => this.handleFieldChange(e)} /> </div> <div> <label for="">地址</label> <input type="text" name="addr" value={formData.addr} onChange={e => this.handleFieldChange(e)} /> </div> </div> ) } } 为了让代码更简洁,我把 通过这个例子,还希望大家能体会到组件拆分的一个好处。就是, 好啦,关于第三个场景我想就没有必要再实现一遍了,Repeat 嵌套多少层其实都是可以的。 更进一步实际上在实际应用中,Repeat 这个组件还需要做进一步完善,其中一个就是样式,还有可能在不同的场景下,虽然交互都是这样,但样式会有所差异。另外默认是“添加”、“移除”两个文字按钮,说不定实际业务场景中是两个 +,- 的图标按钮;还有可能“添加”、“移除”的位置为有所变化。 这些问题怎么处理呢?下面给大家描述下思路,具体代码就不写了,如果有什么疑问可以给我留言。
最后这是本篇文章的代码:https://codepen.io/Sarike/pen... 好啦,文章就到这吧,如果有什么疑问可以给我留言。谢谢大家,祝大家国庆、中秋节快乐。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |