react-props扩展

react - props用法扩展

props.children 模拟vue中的插槽

简单实用函数组件模拟插槽,和具名插槽

   const Child = ({children}) => {
        return(
            <div>
            {/* 具名插槽实现 , 对应元素的具体使用*/}
            <div> {children.find(itm => itm.props.name === 'header')}</ div>
            <h3>具名插槽</ h3>
            <div>{ children.find(itm => itm.props.name === 'footer')}</ div>
            
            <hr />
            {/* 直接将拿到的数据全部展示*/}
            <h3>简单插槽</ h3>
            <div>{children}</ div>
            </ div>
        )
   } 
   
    const Farther = () => {
        return (
            <div>
            <h3>父组件</ h3>
            
            {/*
                1, 子组件中的元素,可以通过props.children获取, 可以直接结构
                2, 如果只有一个元素,返回的是一个对象,如果有多个元素返回的就是一个对象数组
              */}
            <Child>
                <div name="header">我是头</ div>
                <div name="footer">我是尾</ div>
            </ Child>
            </ div>
        )
    }
`

### 模拟作用域插槽
>理解作用域插槽: 实现组件间数据传递和内容复用的技术 , 他允许父组件在子组件模版中自定义内容,同时还可以在访问到子组件时, 提供数据给父组件

```javascript
const AppChildren = ({ children }) => {
  const name = '迂幵'
  // 使用内置方法判断当前的children属性是对象还是数组,写法上都是以数组方式些
  const childs = React.Children.map(children, (child) => {
    // 在使用内置方法,克隆一个属于自己的组件
    return React.cloneElement(child, {
      onClick: () => {
        // 调用的是父组件中的子组件插槽传过来的点击事件 , 并将当前子组件中的数据,传入到父的子模版中
        child.props.onClick(name)
      }
    })
  })
  return (
    <div>
      <div>子组件</div>
      <hr />
      {childs}
    </div>
  );
}


const AppFarther = () => {
  const clickHandler = (name) => {
    console.log('2222' , name)
  }
  return (
    <div>
      <h3 >我是父组件</h3>

      <AppChildren>

        <div onClick={clickHandler}>点我,快点我</div>

      </AppChildren>
    </div>
  );
}

使用类组件模拟插槽

class AppChildrenCalss extends Component {
  render() {
    // 如果是写好了的子组件内容,可以直接调用即可
    const {children} = this.props
    // 是一个数组,每个jsx元素都是一个对象,定义在标签上的属性就是props值
    console.log(children)

    // 如果要拿到子组件内容后要修改显示内容或者样式之类的
    // 要修改的话一定要先克隆下来,不一定非用map , forEach也可以
    const Children = React.Children.map(this.props.children , child => {
      return React.cloneElement(child , {style : {color : 'red'}} , '这里修改显示内容')
    })
    return (
      <div>
        <h3>子组件</h3>
        <hr />
        {/* 修改的是克隆的,所以原本传过来的组件并不受影响,可以一块使用 */}
        {children}
        {Children}
        
        <hr />
        <hr />
        {/* 实现具名插槽 , 匿名插槽默认是有名字的: default */}
        {children.find(child => child.props.name === 'header')}
        {children.find(child => child.props.name === 'default' || !child.props.name)}
        {children.find(itm => itm.props.name === 'footer')}
      </div>
    );
  }
}


class AppChildrenCalss_F extends Component {
  render() {
    return (
      <div>
        <h3>父组件</h3>

        <AppChildrenCalss>
          <div>子组件的内容</div>
        </AppChildrenCalss>
      </div>
    );
  }
}

prop-types : 类型限制

react15.5之后,使用它时要重新安装 * npm i -S prop-types*
在自己封装公共组件的时候一定要用到,根据具体的业务需求封装的组件中值的类型也有一定限制
起作用: 来限制props类型,props本身可以是任意类型的数据,写法类似Ts,类组件函数组件都支持
资料查阅地址: react-propTypes

// 代码演示     函数组件

import React from 'react';
import types from 'prop-types'

const AppPropTypes = () => {
  return (
    <div>
      <h1>父组件</h1>
      <AppPropTypesChild
        countent='100'
        arr={[1, 'w3', 3, function a() { console.log('a') }(), 4]}
        obj={{ id: 1, name: '2', c: () => { console.log('func') } }}
        el={
          <div>
            <div>aaa</div>
            <div>bbb</div>
          </div>
        }
        sex = '2'
        text = 'aldsjfoajdojcoaidt'
      />

    </div>
  );
}

const AppPropTypesChild = (props) => {
  return (
    <div>
      {/* 如过展示的是数组中的函数的话,要么在存的时候字调用,要么在此处调用,不能直接展示函数体 */}
      {props.obj.a} --- {props.countent} --- {props.arr[3]}
    </div>
  );
}
// 限制子组件中接受到的值的类型,如果值得类型不符合限制类型,使用时可以正常使用,但控制台会有报错.这种写法,类组件,函数组件都可以用
AppPropTypesChild.propTypes = {
  // countent的值只能是一个数字类型
  // countent : types.number,
  // countent值必须要有并且是一个数字类型
  // countent : types.number.isRequired,
  // 设置为字符串类型
  // countent : types.string,
  // 字段类型可选,上中下摇摆
  countent: types.oneOfType([types.string, types.number, types.any]),
  // 字段类型为数组
  // arr : types.array,
  // 具体到数组中的每个元素的类型  所有的元素类型都一样的情况
  // arr : types.arrayOf(types.number),
  // 数组中的元素的值类型不同
  arr: types.arrayOf(types.oneOfType([types.string, types.number, types.bool, types.func])),
  // 对象类型,这样写的范围太广了
  obj : types.object,
  // 限制对象中属性的类型,具体对应每一个,没对应到的会报错
  obj: types.shape({
    id : types.number,
    name : types.string,
    c : types.func
  }),
  // 元素类型
  el: types.node,
  // 枚举类型, 赋值正能在规定的范围内 '1' 或者 '2'
  sex : types.oneOf(['1','2']),
  // 自定义验证
  text : (props , propName , componentName) => {
    if(props[propName].includes('t')){
      return new Error('有敏感词t出现')
    }
  }

}

export default AppPropTypes;

在类组件中还可以换一种写法,写前先来明确一点: class.shuxing 此属性是一个静态属性 ===> Child.propTypes={} 就可以理解为在类中定义一个静态属性
在导入types时,可以直接将进行结构,不过这样挺麻烦的,还是别结构了

import {string , number , array , onOF ,...} from 'prop-typs'
class Child extends Component{
    static propTypes = {
        countent : string,
        .....
    }
}

props的默认值设置

组件中提过,在子组件中可以对父组件传过来的props进行结构,并赋予初始值,但是这有缺陷
结构式需要开发者调用组件时,一定要定义默认值,如果不设置,可能造成组件异常,不安全

// 具体定义默认值的写法,函数/类组件通用的,很简单
Child.defaultProps = {
    count : 100,
    .... 
}

你可能感兴趣的:(react,react.js,vue.js,javascript)