使用第三方组件 安装: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 形式,而且要注意是浅比较
