美文网首页程序员
react深入(0-1)-高阶组件HOC,表单,弹窗(Porta

react深入(0-1)-高阶组件HOC,表单,弹窗(Porta

作者: 申_9a33 | 来源:发表于2021-02-13 10:27 被阅读0次

1.HOC

1.1HOC 基本使用

简介:HOC是一个函数,接受一个组件,返回一个新组件

// HocPage.js
import React, { Component } from 'react'

// 定义一个Hoc函数
const foo = Com =>props=>{
  return (
    <div className="border">
      <Com {...props}/>
    <div>
  )
}

function child(props){
  return <div> child:{props.name}</div>
}


const Foo = foo(child)

export default class HocPage extents Component {
  render(){
    return (
        <div>
          <h3>HocPage</H3>
          <Foo name="msg"/>
        </div>
    )
  }
}

1.2 HOC 链式调用 (因为其原理:入参和返回始终是一个组件,所以可以无限链式调用,最终返回的还是一个组件)

import React, { Component } from 'react'


// hoc:是一个函数,接受一个组件,返回另一个组件
const foo = Cmp => props => {
    return (
        <div className='border'>
            <Cmp {...props} />
        </div>
    )
}

const foo2 = Cmp => props => {
    return (
        <div className="hotpinkBorder">
            <Cmp {...props} />
        </div>
    )
}

function Child(props) {
    return <div>Child {props.name}</div>
}
const Foo = foo2(foo(foo(Child)));


export default class HocPage extends Component {
    render() {
        return (
            <div>
                <h3>hocPage</h3>
                <Foo name="msg"></Foo>
            </div>
        )
    }
}

1.3 使用装饰器

  • 1.3.1 安装插件
npm install react-app-rewired customize-cra --save-dev
npm install -D @babel/plugin-proposal-decorators
  • 1.3.2 增加配置文件
// config-overrides.js

const { addDecoratorsLegacy, override } = require("customize-cra");

module.exports = override(
    addDecoratorsLegacy()
)
  • 1.3.3 修改package.json
/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test --env=jsdom",
+   "test": "react-app-rewired test --env=jsdom",
}

+1.3.4 使用

import React, { Component } from 'react'


// hoc:是一个函数,接受一个组件,返回另一个组件
const foo = Cmp => props => {
    return (
        <div className='border'>
            <Cmp {...props} />
        </div>
    )
}

const foo2 = Cmp => props => {
    return (
        <div className="hotpinkBorder">
            <Cmp {...props} />
        </div>
    )
}

// 从下往上
@foo2
@foo
@foo
class Child extends Component {
    render() {
        return <div>Child</div>;
    }
}

export default class HocPage extends Component {
    render() {
        return (
            <div>
                <h3>hocPage</h3>
                {/* <Foo name="msg"></Foo> */}
                <Child name="msg" />
            </div>
        )
    }
}

注意:不要在render方法中使用HOC


2.设计表单组件

2.1 antd 表单基本使用


import React, { Component } from 'react'
import { Form, Input, Button } from 'antd'

export default class FromPage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            name: "",
            password: ""
        }
    }

    submit() {
        console.log("submit", this.state)
    }

    render() {
        const { name, password } = this.state;

        return (
            <div>
                <h3>FromPage</h3>

                <Form>
                    <Form.Item label="姓名">
                        <Input placeholder="请输入姓名"
                            value={name}
                            onChange={e => {
                                this.setState({ name: e.target.value })
                            }}>
                        </Input>
                    </Form.Item>
                    <Form.Item label="密码">
                        <Input type='password' placeholder="请输入密码"
                            value={password}
                            onChange={e => {
                                this.setState({ password: e.target.value })
                            }}>
                        </Input>
                    </Form.Item>

                    <Button type='primary' onClick={this.submit.bind(this)}>提交</Button>
                </Form>
            </div>
        )
    }
}

2.2 自己实现From组件

2.2.1 创建一个from组件的HOC

// FromCreate.js
import React, { Component } from 'react'

export default function kFromCreate(Cmp) {
    return class extends Component {
        constructor(props) {
            super(props);
            this.state = {};
            this.options = {};
        }

        handleChange = e => {
            let { name, value } = e.target

            this.setState({ [name]: value })
        };

        getFieldDecorator = (field, option) => {
            this.options[field] = option;

            return InputCmp =>
                React.cloneElement(InputCmp, {
                    name: field,
                    value: this.state[field] || "",
                    onChange: this.handleChange
                })
        }

        getFieldsValue = () => {
            return { ...this.state }
        }

        getFiledValue = (field) => {
            return this.state[field]
        }

        validateFields = callback => {
            let errors = {};

            const state = { ...this.state };

            console.log(state, this.options)
            for (const key in this.options) {
                if (state[key] === undefined) {
                    errors[key] = "error"
                }
            }

            if (JSON.stringify(errors) === "{}") {
                callback(undefined, state)
            } else {
                callback(errors, state);
            }
        }

        render() {
            return (
                <div className='border'>
                    <Cmp
                        {...this.props}
                        getFieldDecorator={this.getFieldDecorator}
                        getFieldsValue={this.getFieldsValue}
                        getFiledValue={this.getFiledValue}
                        validateFields={this.validateFields} />
                </div>
            )
        }
    }
}

2.2.2 创建From组件

// MyFromPage.js
import React, { Component } from 'react'
import MyFromCreate from './FromCreate'

// 校验规则
const nameRules = { required: true, message: "请输入姓名" }
const passwordRules = { required: true, message: "请输入密码" }


export default MyFromCreate(
    class MyFromPage extends Component {
        submit = () => {
            const { getFieldsValue, getFiledValue, validateFields } = this.props

            console.log(getFieldsValue(), getFiledValue('name'))
            validateFields((err, values) => {
                if (err) {
                    console.error(err)
                } else {
                    console.log(values)
                }
            })
        }

        render() {
            console.log("props", this.props)
            const { getFieldDecorator } = this.props

            return (
                <div>
                    <h3>MyFromPage</h3>
                    {getFieldDecorator('name', { rules: [nameRules] })(
                        <input type="text" placeholder="请输入用户名"></input>
                    )}

                    {
                        getFieldDecorator('password', { rules: [passwordRules] })(
                            <input type="password" placeholder="请输入密码"></input>
                        )
                    }

                    <button onClick={this.submit}>提交</button>
                </div>
            )
        }
    }
)

3.设计弹窗组件

3.1 封转dialog样式

// dialog.js
import React, { Component } from 'react'
import { createPortal } from 'react-dom'

export default class Dialog extends Component {
    constructor(props) {
        super(props)

        this.node = document.createElement('div')
        this.node.classList.add("sss")

    }

    componentDidMount() {
        document.body.appendChild(this.node)
    }

    componentWillUnmount() {
        document.body.removeChild(this.node)
    }

    render() {
        const { hideDialog, children } = this.props
        return createPortal(
            <div>
                {children}
                {typeof hideDialog == "function" && (
                    <button onClick={hideDialog}>关闭窗口</button>
                )}
            </div>, this.node)
    }
}

3.2 使用dialog

// DialogPage.js
import React, { Component } from 'react'
import Diallog from './Diallog'

export default class DialogPage extends Component {
    constructor(props) {
        super(props)

        this.state = {
            isShowDialog: false
        }
    }

    render() {
        const { isShowDialog } = this.state;
        return (
            <div>
                <h3>DialogPage</h3>
                <button onClick={() => this.setState({
                    isShowDialog: !isShowDialog
                })}>
                    toggle
                </button>
                {isShowDialog && <Diallog children="hello" hideDialog={() => this.setState({
                    isShowDialog: false
                })} />}
            </div>
        )
    }
}

源码连接

相关文章

网友评论

    本文标题:react深入(0-1)-高阶组件HOC,表单,弹窗(Porta

    本文链接:https://www.haomeiwen.com/subject/zkgdxltx.html