Skip to content

命令式调用你的 React web 组件 #68

@huruji

Description

@huruji

大多数时候,是这样使用 React 组件的:

通过显示地修改传递给组件的 props 来改变组件的状态(显隐、颜色、内容等),这在大多数时候非常好用,并且这就是 React 的设计哲学,这属于声明式调用,但考虑一下我们经常用到的弹框组件(toast、modal、loading),因为弹框组件会被经常调用,并且可能同时存在多个实例,这样就需要维护多个props的状态,同时还需要手动修改父组件的 state 来控制显隐,这是非常繁琐的。

类似于 antd 的message 的使用方式 message.info('This is a normal message') ,antd 称其为全局提示组件。

这种调用方式就是命令式调用,这种调用方式非常类似于以往 jQuery 时代的js库,好处在于不再需要不断地维护 组件 的状态,这对于 toastmodalloading 来说非常有用。

其实设计这样一个组件并不难,其核心在于主动调用 ReactDOM.render 方法,将组件渲染上去,以设计一个 toast info 组件为例:

首先编写普通的 react 组件:

import React from 'react'
import ReactDOM from 'react-dom'

export interface InfoProps {
	/**
	 * 提示消息
	 */
	msg: string
	/**
	 * 图标类型,none,info,fail,success
	 * 默认为 none
	 */
	icon?: string
}

export default class Info extends React.Component<InfoProps, any> {
	public defaultProps: InfoProps = {
		msg: '',
		icon: 'none'
	}

	render() :React.ReactNode{
		const { icon, msg } = this.props
		const showIcon = icon !== 'none'
		const iconClass = `icon ${icon !== 'info' ? 'icon_' + icon : ''}`
		return (
			<div className="mod_alert_v2 show fixed">
				{showIcon ? <i className={iconClass} /> : null}
				<p>{msg}</p>
			</div>
		)
	}
}

暴露一个普通方法,来手动挂载到页面上去

import React from 'react'
import ReactDOM from 'react-dom'
import Info, { InfoProps } from './Info'

export default function info(
	opts: InfoProps & {
		/**
		 * 计时消失毫秒数,默认 2000
		 */
		delay?: number
		/**
		 * 是否显示蒙层
		 * 默认不显示
		 */
		showcoverdiv?: boolean
	} = {
		msg: ''
	}
) {
	const options = Object.assign(
		{
			msg: '',
			delay: 2000,
			icon: 'none',
			showcoverdiv: false
		},
		opts
	)

	const div = document.createElement('div')
	document.body.appendChild(div)
	ReactDOM.render(<Info msg={options.msg} icon={options.icon} />, div)

	setTimeout(() => {
		ReactDOM.unmountComponentAtNode(div)
		document.body.removeChild(div)
	}, options.delay)
}

其核心就是通过 ReactDOM.render 来挂载上去的,通过 ReactDOM.unmountComponentAtNode 来卸载组件的。

简单的调用方式如下:

通过这种方式,可以很快地封装好你的 React 命令式组件,以个人经验而言,对于 web 常用的 toastmodalloading 这三种组件应该是封装为这种组件会更加方便使用的。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions