zoukankan      html  css  js  c++  java
  • 二、React组件化

    使用第三方组件

    安装: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 形式,而且要注意是浅比较

  • 相关阅读:
    Docker安装及基本命令
    SpringBoot-获取YAML文件值
    SpringBoot-YAML语法
    Maven仓库
    第一次使用Maven
    初始Maven
    索引的基本使用与创建选择
    了解索引为什么能快速查找数据
    Mysql的执行顺序与优化分析
    Mysql常用的几种join连接方式
  • 原文地址:https://www.cnblogs.com/haishen/p/11698952.html
Copyright © 2011-2022 走看看