目录
一、Props 是什么
二、props children模式
1. props 插槽组件
2. render props模式
3. render props模式
三、进阶实践
一、Props 是什么
先来看一个 demo :
function Chidren(){
return 我是子组件
}
/* props 接受处理 */
function Father(props) {
const { children , mes , renderName , say ,Component } = props
const renderFunction = children[0]
const renderComponent = children[1]
/* 对于子组件,不同的props是怎么被处理 */
return (
{ renderFunction() }
{ mes }
{ renderName() }
{ renderComponent }
)
}
/* props 定义绑定 */
class App extends React.Component{
state={
mes: "hello,React"
}
node = null
say= () => this.setState({ mes:'let us learn React!' })
render(){
return
my name is YinJie } // ④ props 作为渲染函数
>
{ ()=> hello,world } { /* ⑤render props */ }
{ /* ⑥render component */ }
}
}
我们看一下输出结果:
当点击触发更改时就能够调用回调更改数据源:
所以 props 可以是:
① props 作为一个子组件渲染数据源。
② props 作为一个通知父组件的回调函数。
③ props 作为一个单纯的组件传递。
④ props 作为渲染函数。
⑤ render props , 和④的区别是放在了 children 属性上。
⑥ render component 插槽组件。
二、props children模式
我们先来看看 prop + children 的几个基本情况:
1. props 插槽组件
上述可以在 Container 组件中,通过 props.children 属性访问到 Children 组件,为 React element 对象。
作用:
可以根据需要控制 Children 是否渲染。
像上一节所说的, Container 可以用 React.cloneElement 强化 props (混入新的 props ),或者修改 Children 的子元素。
举一个用React.cloneElement 强化 props 的例子,多用于编写组件时对子组件混入新的 props,下面我们要做一个导航组件,我们希望它的结构如下:
我们想给每个 MenuItem 子组件都添加 index 属性,这个事情不应该让用户手动添加,最好是可以在 Menu 组件中自动为每个 MenuItem 子组件添加上,并且 Menu 组件还应该判断子组件的类型,如果子组件的类型不是 MenuItem 组件就报错。
Menu.tsx:
const Menu: React.FC = (props) => {
// ... 一些操作
const renderChildren = () => { // 让子级的children都是 menuItem,有不是的就报错
return React.Children.map(children, (child, index) => {
const childElement = child as React.FunctionComponentElement
const { displayName } = childElement.type
if(displayName === 'MenuItem' || displayName === "SubMenu") {
return React.cloneElement(childElement, { index: index.toString() })
} else {
console.error('warning: Menu has a child whitch is not a MenuItem')
}
})
}
return (
{renderChildren()}
)
}
在 Menu 组件中我们通过 React.children.map 来循环子组件,通过 child.type 可以获取到每个子组件的 displayName 静态属性,这个在子组件中有定义:
通过子组件的 displayName 来判断是否是我们需要的 MenuItem,如果是的话就调用 React.cloneElement 来为子组件添加 index 属性。
2. render props模式
{ (ContainerProps)=> }
这种情况,在 Container 中, props.children 属性访问到是函数,并不是 React element 对象,我们应该调用这个函数:
function Container(props) {
const ContainerProps = {
name: 'alien',
mes:'let us learn react'
}
return props.children(ContainerProps)
}
这种方式作用是:
1 根据需要控制 Children 渲染与否。
2 可以将需要传给 Children 的 props 直接通过函数参数的方式传递给执行函数 children 。
3. render props模式
如果 Container 的 Children 既有函数也有组件,这种情况应该怎么处理呢?
{ (ContainerProps)=> }
const Children = (props)=> (
hello, my name is { props.name }
{ props.mes }
)
function Container(props) {
const ContainerProps = {
name: 'alien',
mes:'let us learn react'
}
return props.children.map(item=>{
if(React.isValidElement(item)){ // 判断是 react elment 混入 props
return React.cloneElement(item,{ ...ContainerProps },item.props.children)
}else if(typeof item === 'function'){
return item(ContainerProps)
}else return null
})
}
const Index = ()=>{
return
{ (ContainerProps)=> }
}
这种情况需要先遍历 children ,判断 children 元素类型:
针对 element 节点,通过 cloneElement 混入 props ;
针对函数,直接传递参数,执行函数。
三、进阶实践
实现一个简单的