使用第三方组件 安装:npm install antd --save 试用 ant-design 组件库 import React, { Component } from ‘react‘ import Button from ‘antd/lib/button‘ ; import ‘antd/dist/antd.css‘ export default class TestAntd extends
使用第三方组件
安装:npm install antd --save
试用 ant-design 组件库
import React, { Component } from ‘react‘
import Button from ‘antd/lib/button‘; import ‘antd/dist/antd.css‘ export default class TestAntd extends Component { render() { return ( <div> <Button type="primary">Button</Button> </div> ) } }
上面 import 的内容太长,不利于日常开发
配置按需加载
安装 react-app-rewired 取代 react-scripts,可以扩展webpack的配置,类似 vue.config.js
npm install react-app-rewired customize-cra babel-plugin-import -D
// 根目录创建 config-overrides.js
const { override, fixBabelImports, addDecoratorsLegacy } = require("customize-cra")
module.exports = override( fixBabelImports("import", { libraryName: "antd", libraryDirectory: "es", style: "css" }), addDecoratorsLegacy() // 配置装饰器,这里如果配置,需要先安装下面的npm )
修改package.json
"scripts": {
"start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" }
支持装饰器配置
npm install -D @babel/plugin-proposal-decorators
例如:高级组件链式调用
import React, { Component } from ‘react‘
const foo = Cmp => props => { return <div style={{border: ‘1px solid red‘}}> <Cmp {...props}/> </div> } const foo2 = Cmp => props => { return <div style={{border: ‘1px solid green‘, padding: ‘10px‘}}> <Cmp {...props}/> </div> } function Child(props){ return <div>Child</div> } export default class HocPage extends Component { render() { const Foo = foo2(foo(Child)) return ( <div> <h1>HocPage</h1> <Foo /> </div> ) } }
改为装饰器的写法:装饰器只能用于装饰 class 组件
import React, { Component } from ‘react‘
const foo = Cmp => props => { return <div style={{border: ‘1px solid red‘}}> <Cmp {...props}/> </div> } const foo2 = Cmp => props => { return <div style={{border: ‘1px solid green‘, padding: ‘10px‘}}> <Cmp {...props}/> </div> } @foo2 @foo class Child extends Component { render(){ return <div>Child</div> } } export default class HocPage extends Component { render() { return ( <div> <h1>HocPage</h1> <Child /> </div> ) } }
注意:需要引入 antd样式文件: import ‘antd/dist/antd.css‘;
使用antd的Form表单
import React, { Component } from ‘react‘
import {Form, Input, Icon, Button} from ‘antd‘ const FormItem = Form.Item export default class FormPage extends Component { constructor(props){ super(props) this.state = { name: ‘‘, password: ‘‘ } } change = (field, event)=>{ this.setState({ [field]: event.target.value }) } submit = ()=>{ console.log(‘state‘, this.state); } render() { return ( <div> <h1>FormPage</h1> <Form> <FormItem label="姓名"> <Input prefix={<Icon type="user"/>} onChange={event => this.change(‘name‘, event)}/> </FormItem> <FormItem label="密码"> <Input type="password" prefix={<Icon type="lock"/>} onChange={event => this.change(‘password‘, event)}/> </FormItem> <FormItem> <Button type="primary" onClick={this.submit}>提交</Button> </FormItem> </Form> </div> ) } }
Form中内容的使用 --- Form.create()
import React, {Component} from ‘react‘
import {Form, Input, Icon, Button} from ‘antd‘ const FormItem = Form.Item class FormPageDecorators extends Component { submit = () => { const { getFieldsValue, getFieldValue } = this.props.form // 获取所有Field的值 console.log(‘submit‘, getFieldsValue()); // 获取单个值 console.log(‘submitName‘, getFieldValue(‘name‘)); } render() { // 装饰器 const {getFieldDecorator} = this.props.form console.log(this.props.form); return ( <div> <h1>FormPageDecorators</h1> <Form> <FormItem label="姓名"> { getFieldDecorator(‘name‘)(<Input prefix={< Icon type = "user" />}/> )} </FormItem> <FormItem label="密码"> { getFieldDecorator(‘password‘)(<Input type="password" prefix={< Icon type = "lock" />}/> )} </FormItem> <FormItem> <Button type="primary" onClick={this.submit}>提交</Button> </FormItem> </Form> </div> ) } } export default Form.create()(FormPageDecorators)
表单验证
// 校验规则
const nameRule = {
required: true, message: ‘please input your name‘ } const passwordRule = { required: true, message: ‘please input your password‘ } class FormPageDecorators extends Component { submit = () => { const { validateFields } = this.props.form // 表单验证 validateFields((err, values)=>{ if(err){ console.log(‘err:‘, err) }else{ console.log(‘submit:‘, values); } }) } } <FormItem label="姓名"> { getFieldDecorator(‘name‘, {rules: [nameRule]})(<Input prefix={< Icon type = "user" />}/> )} </FormItem> <FormItem label="密码"> { getFieldDecorator(‘password‘, {rules: [passwordRule]})(<Input type="password" prefix={< Icon type = "lock" />}/> )} </FormItem>
自己写一个Form.create()
import React, { Component } from ‘react‘ function kFormCreate(Cmp){ return class extends Component { constructor(props){ super(props) this.options = {} // 配置字段项 this.state = {} // 存字段值 } handleChange = (event)=>{ const {name, value} = event.target this.setState({ [name]: value }) } getFieldDecorator = (field, options)=>{ this.options[field] = options return InputCmp=>( <div className="border"> {React.cloneElement(InputCmp,{ name: field, value: this.state[field] || "", onChange: this.handleChange })} </div> ) } getFieldsValue = ()=>{ return {...this.state} } getFieldValue = (field)=>{ return this.state[field] } validateFields = (callback)=>{ const tem = {...this.state} const err = [] for(let i in this.options){ if(tem[i] === undefined){ err.push({ [i]: ‘error‘ }) } } if(err.length>0){ callback(err, tem) }else{ callback(undefined, tem) } } render(){ return ( <div className="border"> <Cmp {...this.props} getFieldDecorator={this.getFieldDecorator} getFieldsValue={this.getFieldsValue} getFieldValue={this.getFieldValue} validateFields={this.validateFields} /> </div> ) } } } // 校验规则 const nameRule = { required: true, message: ‘please input your name‘ } const passwordRule = { required: true, message: ‘please input your password‘ } class MyFormPage extends Component { submit = ()=>{ const {getFieldsValue, getFieldValue, validateFields} = this.props validateFields((err, values)=>{ if(err){ console.log(‘err‘, err); }else{ console.log(‘submitSuccess:‘,values); } }) } render() { const {getFieldDecorator} = this.props return ( <div> <h1>MyFormPage</h1> { getFieldDecorator(‘name‘,{rules: [nameRule]})( <input type="text"/> ) } { getFieldDecorator(‘password‘,{rules: [passwordRule]})( <input type="password"/> ) } <button onClick={this.submit}>提交</button> </div> ) } } export default kFormCreate(MyFormPage)
Dialog组件(弹窗组件)
Dialog.js
import React, { Component } from ‘react‘ import {createPortal} from ‘react-dom‘; export default class Dialog extends Component { constructor(props){ super(props) const doc = window.document this.node = doc.createElement(‘div‘) doc.body.appendChild(this.node) } componentWillUnmount(){ window.document.body.removeChild(this.node) } render() { return createPortal( <div className="dialog"> <h1>Dialog</h1> </div>, this.node ) } }
DialogPage.js
import React, { Component } from ‘react‘ import {Button} from ‘antd‘; import Dialog from ‘../components/Dialog‘; export default class DialogPage extends Component { constructor(props){ super(props) this.state = { showDialog: false } } handleShowDialog = ()=>{ this.setState({ showDialog: !this.state.showDialog }) } render() { const {showDialog} = this.state return ( <div> <h1>DialogPage</h1> <Button onClick={this.handleShowDialog}>dialog toggle</Button> { showDialog && <Dialog /> } </div> ) } }
树形组件
css文件
.tri { width: 20px; height: 20px; margin-right: 2px; padding-right: 4px; } .tri-close:after, .tri-open:after { content: ""; display: inline-block; width: 0; height: 0; border-top: 6px solid transparent; border-left: 8px solid black; border-bottom: 6px solid transparent; } .tri-open:after { transform: rotate(90deg); }
TreeNode.js
import React, { Component } from ‘react‘ import classnames from ‘classnames‘; export default class TreeNode extends Component { constructor(props){ super(props) this.state = { expanded: false } } handleExpanded = ()=>{ this.setState({ expanded: !this.state.expanded }) } render() { const {title, children} = this.props.data const {expanded} = this.state const hasChildren = children && children.length > 0 return ( <div> <div className="nodesInner" onClick={this.handleExpanded}> { hasChildren && <i className={classnames("tri", expanded ? ‘tri-open‘:‘tri-close‘)}></i> } <span>{title}</span> </div> { hasChildren && expanded && <div className="children"> { children.map(item=>{ return <TreeNode key={item.key} data={item}/> }) } </div> } </div> ) } }
TreePage.js
import React, { Component } from ‘react‘ import TreeNode from ‘../components/TreeNode‘; //数据源 const treeData = { key: 0, //标识唯?一性 title: "全国", //节点名称显示 children: [ //?子节点数组 { key: 6, title: "北方区域", children: [{ key: 1, title: "?龙江省", children: [{ key: 6, title: "哈尔滨", }, ], }, { key: 2, title: "北京", }, ], }, { key: 3, title: "南方区域", children: [{ key: 4, title: "上?", }, { key: 5, title: "深圳", }, ], }, ], }; export default class TreePage extends Component { render() { return ( <div> <h1> TreePage </h1> <TreeNode data={treeData}/> </div> ) } }
常见组件优化技术
定制组件的 shouldComponentUpdate 钩子
import React, { Component } from ‘react‘ export default class CommentList extends Component { constructor(props){ super(props) this.state = { comments: [] } } componentDidMount(){ setInterval(() => { this.setState({ comments: [{ author: "?明", body: "这是小明写的?文章", }, { author: "小红", body: "这是小红写的?文章", }] }) }, 1000); } render() { const {comments} = this.state return ( <div> <h1>CommentList</h1> { comments.map(item=>{ return <Comment key={item.author} data={item}/> }) } </div> ) } } class Comment extends Component{ shouldComponentUpdate(nextProps, nextState){ const {author, body} = nextProps const {author: nowAuthor, body: nowBody} = nextProps if(author===nowAuthor && body === nowBody) { return false } } render(){ const {author, body} = this.props.data console.log(‘render‘); return <div className="border"> <p>作者: {author}</p> <p>内容: {body}</p> </div> } }
PureComponent
import React, { Component, PureComponent } from ‘react‘ export default class PureConponentPage extends Component { constructor(props){ super(props) this.state = { counter: 0 } } setCounter = ()=>{ this.setState({ counter: 1 }) } render() { const {counter} = this.state return ( <div> <h1>PureConponentPage</h1> <button onClick={this.setCounter}>change</button> <Demo counter={counter}/> </div> ) } } class Demo extends PureComponent{ render(){ const {counter} = this.props console.log(‘render‘); return <div> {counter} </div> } }
缺点是必须要用 class 形式,而且要注意是浅比较