Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react 组合模式 #16

Open
yaogengzhu opened this issue Sep 13, 2021 · 0 comments
Open

react 组合模式 #16

yaogengzhu opened this issue Sep 13, 2021 · 0 comments

Comments

@yaogengzhu
Copy link
Owner

React组合模式

通过React.children.forEach 遍历props.children

function Groups(props) {
	console.log(React.Children, 'React.children')
	React.Children.forEach(props.children, item => {
		console.log(props.children)
		console.log(item.props) //依次打印 props
	})
	return props.children
}

function Item(props) {
	return <div>名称:{props.name}</div>
}

const App = () => {
	return (
		<div>
			<Groups>
				{/* <div>hello</div> */}
				<Item name="react进阶1" />
				<Item name="react进阶2" />
				<Item name="react进阶3" />
			</Groups>
		</div>
	)
}

通过React.cloneElemnet混入props,

/**
 *  React组合模式
 */
function Groups(props) {
	// 隐式混入props, 想好隐式混入props,必须通过React.cloneElement方式
	// const newChildren = React.cloneElement(props.children, { author: 'zhuyaogeng'})
	// 可以指定节点进行混入
	const newChildren = React.Children.map(props.children, item => {
		const { isBelongTo } = item.props || {}
		console.log(isBelongTo, 'xxx')
		if (isBelongTo ) {
			return React.cloneElement(item, { author: 'zhuyaogeng' })
		}
		return React.cloneElement(item)
	})
	return newChildren
}

function Item(props) {
	console.log(props, 'zi') // {name: 'react进阶2', author: 'zhuyaogeng'}
	return <div>名称:{props.name}</div>
}

组合模式,实现内外层通信

function Groups(props) {
	// 可以挂载一个callback回调
	const newChildren = React.Children.map(props.children, item => {
		const { isBelongTo } = item.props || {}

		const callback = (val) => {
			console.log(val, '??')
		}
		if (isBelongTo ) {
			return React.cloneElement(item, { author: 'zhuyaogeng', callback })
		}
		return React.cloneElement(item)
	})
	return newChildren
}

function Item(props) {
	// 组合模式,实现内外层通信
	return <div  onClick={() =>  props.callback && props.callback(props.name)} >名称:{props.name}</div>
}

实际应用

import React, { useRef, useState } from 'react'

const Tab = ({ children, onChange }) => {
    const activeIndex = useRef(null)
    const [, forceUpdate] = useState(null)
    const tabList = [] // tabs
    let renderChildren = null

    React.Children.forEach(children, (item) => {
        // 验证是否是element 
        if (React.isValidElement(item) && item.type.displayName === 'tabItem') {
            const { props } = item
            const { name, label } = props
            const tabItem = {
                name,
                label,
                active: name === activeIndex.current,
                component: item
            }
            if (name === activeIndex.current) renderChildren = item
            tabList.push(tabItem)
        }
    })

    if (!renderChildren && tabList.length > 0) {
        const firstChildren = tabList[0]
        renderChildren = firstChildren.component
        activeIndex.current = firstChildren.component.props.name
        firstChildren.active = true
    }

    /* 切换tab */
    const changeTab = (name) => {
        activeIndex.current = name
        forceUpdate({})
        onChange && onChange(name)
    }
    console.log(renderChildren)
    return <div>
        <div className="header">
            {
                tabList.map((tab, index) => (
                    <div key={index} onClick={() => changeTab(tab.name)} >
                        <div className={'text'}  >{tab.label}</div>
                        {tab.active && <div></div>}
                    </div>
                ))
            }
        </div>
        <div>{renderChildren}</div>
    </div>

}
Tab.displayName = 'tab'
export default Tab
const TabItem = ({ children }) => {
    return <div>{children}</div>
}
TabItem.displayName = 'tabItem'

export default TabItem
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant