React

简介

当2014年Facebook推出React时,给整个业界带来全新的看待网页应用开发的方式,和React一同问世的Flux,也克服传统MVC框架的很多弊病。技术在不断发展,在2015年,Flux的一个变体Redux出现,进一步优化了Flux的功能。


优秀之处:

专注视图层:(不处理路由,数据,以及逻辑的处理

VirtualDom只对虚拟dom更新,不对真实dom更新;只对dom进行必要的更新,实现的重绘的最小化;

jsx语法:

• 高内聚,低耦合

• onClick 不是原生dom中的onclick事件,这里是onClict是通过react的事件委托方式,触发挂在顶层dom节点上的一个事件处理函数(提高了性能);

• 可以将样式一起写入组件文件中;

• 关于jsx语法的说法:

• 在jsx语法中可以直接写入组件,注意组件为了和普通标签区别,必须第一个字母大写;

• jsx语法是历史的进步还是倒退;(样式,结构,逻辑于一体)

活跃的生态圈:(开源项目)

组件式开发

手动搭建项目:

• npm init

• 安装项目依赖

cnpm install --save-dev babel-core babel-loader babel-preset-stage-2 babel-plugin-transform-react-jsx babel-plugin-transform-runtime babel-preset-es2015 babel-preset-react babel-preset-stage-0 css-loader html-loader html-webpack-plugin react react-dom style-loader url-loader webpack webpack-dev-server

• 配置babelrc文件:

 {

    "presets": [

        "es2015",

        "stage-0",

        "react"

    ],

    "plugins": ["transform-runtime", "transform-react-jsx"]

}

• webpack.config.js的配置文件:

除了如下配置有更改,其他可以完全遵照vue的配置

{

                test: /\.js|.jsx$/,

                use: [

                    "babel-loader",

                ],

                exclude: /node_modules/

            },

• 在vsCode中开发react的配置:

安装jsx插件配置如下:


安装React/Redux/react-router Snippets插件,可以帮助我们快速生成一定的语句;

所有的react组件使用jsx后缀来标识;

自动化构建项目:

• 初始化:

全局安装:

npm install –-global create- react- app

初始化项目:

create- react- app myReactApp

启动服务:

cd myReactApp

npm start

• 组件写法:


import React,{Component} from "react"

import ClickCount from "./ClickCount.jsx"

class Main extends Component {

  constructor(props){

    super(props)

  }

  render(){

    return (

      

            

  •         

  •         

  •       

    )

  }

}

export default Main

注:对于jsx语法的解析必须引入React,虽然这里不用,但是如果不引入会因无法解析jsx而报错;组件的定义必须遵循首字母大写

• jsx语法使用:

属性:

1、属性值直接为字符串

2、动态解析属性值

const element = ();

react的jsx:

const element = (

  

    Hello, world!

  

);


用React.createElement()同样可以达到同样的效果;

const element = React.createElement(

  'h1',

  {className: 'greeting'},

  'Hello, world!'

);

• 项目的分解:

npm run eject 进行项目配置文件的弹射;

• react的工作方式:

• 从繁琐的dom处理中解脱出来,响应式,函数式编程思维;输入相同的数据,将产出相同的效果;数据更新,dom同时做出更新;

• Virtual Dom

Dom:结构化文本的抽象表达式;

虚拟dom:对dom树的抽象,不会触及浏览器,只存在于js内存的空间树形结构,每次的数据刷新,render函数的执行都会触发一个新旧虚拟dom 的对比,如果无改变,则不更新,有改变,只更新相应dom结构;

元素的渲染

jsx语法将元素渲染到dom

更新元素渲染:

React 元素都是immutable 不可变的。当元素被创建之后,你是无法改变其内容或属性的;更新界面的唯一方法就是重新挂载节点

function tick() {

  const element = (

      

{new Date().toLocaleTimeString()}.

  );

  ReactDOM.render(

    element,

    document.getElementById('root')

  );

}

setInterval(tick, 1000);


只会更新必要的部分(可以在谷歌开发者工具中进行dom更新的查看)

reactjsx语法中,如果标签没有子元素,可以直接使用闭合标签;

react的组件必须首字母进行大写,否则React.createEelement则无法查找到组件,进行编译;

jsx支持标签名为表达式;,如果使用动态标签名,则需先将表达式解析赋值给一个变量;



React组件以及基本语法:

• 组件的设计要素:

高内聚:把逻辑紧密相关的内容放在一个组件中;

低耦合:不同组件之间的依赖关系要尽量弱化;尽量保持每个组件的独立性;

• 组件的生命周期:

• 装载过程:

• Constructor:

初始化state;

绑定成员函数的this环境(bind、:: )防止以解构的方式进行全局作用域进行调用;

例:this.fn=this.fn.bind(this)或this.fn=::this.fn

• GetInitialState:初始化state值,必须结合React.createClass()使用,使用es6的方式,此函数无效果;


const Test=React.createClass({

  getInitialState:function(){

    return {

      name:"zhangsan"

    }

  },

  getDefaultProps:function(){

    return {

      name:"zhangsan" //这里的zhangsan相当于默认值

    }

  }

})


• GetDefaultProps:初始化props值,必须结合React.createClass()使用,使用es6的方式,此函数无效果,用属性defaultProps代替;



class Test extends Component {

  constructor(props){

super(props)

this.state={data:new Date()}

  }

  render(){

    return (

      

            

  •       

    )

  }

}

Test.defaultProps={

    name:"moren"

}



• ComponentWillMount:在render函数调用之前进行调用;

• Render:并不做实际的渲染动作,只返回一个jsx描述结构,最后渲染与否由react来决定;必须是个纯函数,不能设计到数据的更变(this.setState);


render(){

    return (

      

            

  •       

    )

  }


• ComponentDidMount :在render函数调用之后进行调用;但不是在render函数调用之后立即调用,而是当所有的dom树挂载并渲染完成后才会调用,这是因为render函数并不进行渲染,而只是返回一个jsx对象,渲染的工作由react库进行,只有当所有的组件的jsx对象组合完毕之后,react通过对比后才会渲染,所有此钩子函数是发生的所有组件的render函数都执行后才会执行;(只能在浏览器端触发)

注:与angular中的link或者post函数有点相似,但是这里不仅指子组件,而是当前组件中的所有组件,包括兄弟组件;提供了dom操作的接口

• 更新过程:

• ComponentWillReceiveProps:传入的props的改变或者组件进行刷新(forceUpdate函数触发组件的刷新)都会触发此函数,但是通过this.setState改变的数据则不会触发此函数,

• ShouldComponentUpdate:react组件的钩子函数两个需要有返回值的钩子函数之一,另一个为render,此钩子函数的返回值为一个bolen值,如果为true时,则prop的改变以及state的改变都会引起组件的刷新,如果为false时,则不再进行渲染;此钩子函数接受两个参数,一个是nextProps,一个是nextState,可以将将要更新的值和此时的做对比,然后返回true和false来进行性能的校优;

• ComponentWillUpdate:跟componentWillMount相似

• Render

• ComponentDidUpdate:跟componentDidMount相似

• 卸载过程:

ComponentWillUnmount:此钩子函数可以在组件卸载前执行,可以进行手动添加dom元素的删除,以及计时器和事件监听的移除;

React组件的数据

组件内部数据类型:

两种数据结构,prop和state,这两种数据的改变都会引起组件的重新渲染;

• Prop:组件的外部接口,接受外部数据;跟html的属性的书写类似,但是除了接受字符串之外,还可以接受js对象,数字等的;如果组件进行数据反馈给外界,可以通过prop传入组件一个函数;

• Prop的读取:

由class类的constructor函数接受,以及super()方法调用时的传入;

最后的props为一个对象,键值分别为传入时的属性名;这里比较方便的是使用es6的解构赋值;

• PropTypes的检查:

可以通过增加类的propTypes属性来定义prop规格,在constructor函数中进行如下定义:

Index.propTypes={     //组件全局进行配置

caption:PropTypes.string.isRequired,

initValue:PropTypes.number

}

注意:此属性不会影响组件的渲染,只是做到在开发过程中辅助开发;

• State:由于组件不能改变出入的prop,所以当组件要进行自己的状态纪录时就需要用到state;

• 初始化:state的初始化可以在constructor中,通过this.state进行设置,值必须为一个js对象的格式,通常将prop传入的外部值赋给state,以便后续操作;设置默认值时,可以用 | | 操作符进行;

• 读取和更新state

更新使用this.setState({count:this.state.count++})方法;

读取为:this.state.count这种方式

• Prop和state的对比:

Prop:定义外部接口;赋值在外部环境使用组件时;组件内部不能更改

State:纪录内部状态;赋值在组件内部;在组件内部可以进行更改;


reactcss的样式书写

全局引入css文件

此种方式会将css文件在全局引入,也就是说当前样式文件中书写的所有样式,在任何一个组件都可以引用,此种引用方式有可能会造成全局的污染,变量名冲突,又或者说不符合组件式开发的思想;此种方式一般是引入全局的css文件;

import “app.css”


局部作用域(css modules的方式)

此种方式采用的是css modules的做法,通过此做法,最后会将css文件中类名和dom中类名形成唯一的hash值,这样就不会造成类名的冲突了,使用场景,一般为组件内部的样式防止全局书写造成的类名污染;

比如如下写法:

app.css:

.title {

  color: red;

}

jsx:

import style from './App.css';

export default () => {

  return (

    

      Hello World

    

  );

};

最后会编译成如下代码:

  Hello World

._3zyde4l1yATCOkgn-DBWEL {

  color: red;

}


注:在css Modules中还提供了一种css全局作用域的书写方式,也就是说如果通过此种方式注册的css类名不会被替换为hash值,书写方式如下:

css

:global(.title){

color:red;

}


行内样式:

jsxdom上直接使用style属性进行样式的设置,样式的值为一个对象,这种方式的书写,可以支持css样式以js对象的方式进行书写,如果不想将组件的内部样式进行作用域隔离使用css modules的方式进行书写,则可以此种方式进行书写,可以直接在render函数中定义样式对象,也可以通过专门外部样式js文件配置样式对象,然后引入到dom进行使用,书写方式如下:

var style={

color:red;

}

天气真好

注:在书写css属性时,一定要采用驼峰式写法;

事件处理

react中的事件绑定属性采用的是驼峰式写法:

处理react使用class类定义方法时,无法自动绑定this的弊端:

constructor中使用bind为事件函数绑定this

this.clickfn=this.clickfn.bind(this)

dom中调用函数时,先使用箭头函数绑定this,箭头函数的this是在定义时形成的


jsxonClickhtmlonclick不同之处


htmlonclick弊端:

注册的事件处理函数都是全局环境,污染了全局环境;

使用onclick的dom元素,如果在dom树中删除时,必须手动的注销事件处理器,否则会造成内容泄露;


jsxonClick:

挂载的每一个函数都是在组件内部,而不是全局;

无论多少个onClick都是采用的事件委托的方式,在dom树顶层添加一个事件监听函数,此函数会根据具体组件分配具体的函数


条件判断:

reactjsx语法中,如果遇到js语句使用{}进行包裹;

if语句的使用:


render() {

        var element=null

            if(this.state.stateT){

                   element=

stateT为true时 < /div>

                }else{

                     element=

stateT为false时 < /div>

                }

        return (

            

                

                {element}

            

        )

    }


jsx与运算符&&的结合:


render(){

        return (

             

                

                {this.state.stateT&&

stateT为false时 < /div>}

            

        )

    }

三目运算符


render(){

        return (

             

                

                {this.state.stateT?

stateT为true时
:
stateT为false时
}

            

        )

}

jsx语法中,render可以返回null,表示不进行任何dom的渲染,但是钩子函数会执行;

列表和keys

基础用法:(key一般采用数据id,或者数据在数组中的索引)


render() {

        var element=this.state.list.map((i,index)=>

  • {i}
  • )

            return (

                

                    

                    {element}

                

            )

    }

    注:如果后续进行数据的重新排序,则最好不要使用索引当作key值,否则,由于key值和dom的内容同时改变,则会引起全部dom节点的重绘;如果使用的是id,则只会调整dom节点的顺序,不会引起重绘dom树;(可以用上面例子演示,推荐使用id作为标识,而不是index)

    key值只需要在兄弟元素之间唯一就可以,不需要是在全局唯一的


    render() {

            var element=this.state.list.map((i,index)=>

  • {i}
  • )

            var element2=this.state.list.map((i,index)=>

  • {i+1}
  • )

            return (

                

                    

                    {element}

                    {element2}

                

            )

         }

    jsx中使用map进行遍历


    render() {

            return (

                

                      

                     {this.state.list.map((i)=>

    • {i}
    • )}

                  

            )

        }

    表单

    vue中,我们知道由于vuemvvm架构,vm之间是响应式的,可以实时同步,但是在react中不存在数据的双向数据绑定,只是负责view层的渲染,所以我们在react中取表单中的值时需要一定的方式

    受控组件(采用react的单向数据流方式实现vue一样的双向数据绑定)

    changeFn(event){

            this.setState({

                name:event.target.value

            })

        }

        render() {

            return (

                

                    

    表单

                    

                    

                    

    {this.state.name}

                

            )

        }

    如果想对从input中获取到的值进行格式化时,则如下操作就可以实现:

    this.setState({

                name:event.target.value.toUpperCase()

            })

    textarea标签在react中设置和读取值都采用value的方式

    react中的使用select,并实时获取其选择的值:

    render() {

            return (

                

                    

    表单

                    

                    

                    

    {this.state.name}

                

            )

    }

    react中实现多表单元素值得获取

    changeFnAll(event){

            let target=event.target

            let name=target.name

            let value=target.type==="checkbox"?target.checked:target.value

            this.setState({

                [name]:value

            })

        }

        // 实现多表单元素值的获取

        render() {

            return (

                

                    

    表单

       

                    

                    

                    

    {this.state.checkbox.toString()}

                    

    {this.state.text}

                

            )

        }

    组件间通讯

    父组件向子组件传递数据:

    字符串常量的传递:

    没有给属性传值,它默认为 true

    不建议如下写法,容易与es6的对象简洁表示法冲突

    使用扩展运算符进行属性的设置

      const props = {firstName: 'Ben', lastName: 'Hector'};

    ;

    子组件向父组件传递数据

    只能通过将父组件的一个方法用prop的方式传入子组件,在子组件触发更变时,调用这个传入的方法,然后把子组件更变后的值以参数的形式传入父组件;从而达到父组件和子组件的通信的效果;


    兄弟组件间的通讯

    状态提升

    对于没有直接关联关系的两个节点,就如 Child_1 与 Child_2 之间的关系,他们唯一的关联点,就是拥有相同的父组件。参考之前介绍的两种关系的通讯方式,如果我们向由 Child_1 向 Child_2 进行通讯,我们可以先通过 Child_1 向 Parent 组件进行通讯,再由 Parent 向 Child_2 组件进行通讯

    观察者模式

    也就是像angular和vue的事件派发机制,在这里react没有内置的事件派发模式,所以需要手动封装一个事件派发机制;

    如下代码:

    var watchObj = {

        arrFn: {},

        on(name, fn) {

            if (this.arrFn[name] === undefined) {

                this.arrFn[name] = []

            }

            this.arrFn[name].push(fn)

        },

        emit() {

            let name, args;

            if (arguments.length == 0) {

                return false;

            }

            name = arguments[0]

            args = [].concat(Array.prototype.slice.call(arguments, 1));

            if (this.arrFn[name] !== undefined && this.arrFn[name].length > 0) {

                this.arrFn[name].forEach(function(i) {

                    i(...args)

                }, this);

            }

        }

    }

    export default watchObj


    组合与继承

    vue中的有一种组件特性叫内容分发,可以在父组件中自定义子组件的dom结构,在react中也提供了这么一种机制

    包含关系:(在子组件通过this.props.children获取父组件中写在子组件开闭标签间的dom节点)

    父组件:

    render() {

            return (

                

                   

                    

    相当于vue的内容分发

                   

                

            )

        }

    子组件:

    render() {

            return (

                

                    

    这里是子组件

                   {this.props.children}

                

            )

        }


    子组件中动态渲染其他组件:(在父组件中将其他组件动态绑定到prop属性上,在子组件中通过相应的属性来获取)


    父组件:

    render() {

            return (

             var one= 这里为true

            var two=这里为false

            return (

                

                    

                

            )

            )

        }

    子组件:

    render() {

           return 

      

         

     这里是子组件

            {this.state.state?this.props.one:this.props.two}

        

    }


    react-router

     2.0 完全向后兼容 1.0,所有在 1.0 被弃用的 API 都会在控制台以 warn 的形式打印出来,在 3.0 中将会完全移除 1.0 所弃用的东西,现在最新版本是4.2.0版本;但是4.0版本后,有很多方法不再向前兼容(这里讲解的为2.8.1版本)


    基本用法:

    首先我们需要导入一些组件...

    import { Router, Route, Link } from 'react-router'

    配置路由信息:

    使用jsx语法

    React.render((

      

        

          

          

        

      

    ), document.body)

    使用js对象进行配置

    const routes = {

      path: '/',

      component: App,

      childRoutes: [

        { path: 'about', component: About },

        { path: 'inbox', component: Inbox },

      ]

    }

    React.render(, document.body)

    获取参数

    通过动态路由片段

     可以通过如下方式进行获取id

    this.props.params.id

    通过query字符串

    /foo?bar=baz;

    this.props.location.query.bar

    路由的配置规则(Router

    路径语法:

    :paramName – 匹配一段位于 / # 之后的 URL 命中的部分将被作为一个参数

    () – 在它内部的内容被认为是可选的

    * – 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数

    如下解释:

    // 匹配 /hello/michael 和 /hello/ryan

            

    // 匹配 /hello, /hello/michael 和 /hello/ryan

      

    // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg  

             

    常用路由类型:


    browserHistory:react推荐使用(采用的是html5的浏览器路由纪录)

    hashHistory:默认的(采用的是hash的浏览器路由纪录)

    createMemoryHistory


    使用browserHistory如下:

    import { browserHistory } from 'react-router'

    路由的跳转配置(Link):

    需要动态的引入组件:

    import { Link} from “react-router“

    属性:

    to: 值为字符串,例:”/list” (路由跳转的路径);


    query:值为对象,例:{name:1} (这里相当于/list?name=1,这种路由的书写方式);


    state:值为对象,可以通过this.location.state获取到当前的值;


    activeClassName:当某个 route 是激活状态时, 可以接收传入的 className。失活状态下是默认的 class。写法如下:activeClassName="current"


    activeStyle当某个 route 是激活状态时,可以将样式添加到链接元素上;写法如下:activeStyle={{color: 'red'}}


    onClick(e):自定义点击事件的处理方法。如处理  标签一样 - 调用 e.preventDefault() 来防止过度的点击,同时 e.stopPropagation() 可以阻止冒泡的事件


    默认路由的设置:

    jsx:

    js对象:

    const routes = {

      path: '/',

      component: App,

      indexRoute:{

        component:Index

      },

      childRoutes: [

        { path: 'list', component: List },

      ]

    }


    在嵌套路由中使用{this.props.children}来渲染动态路由,这里相当于vue-router中的router-view

    路由对应组件的渲染

    单一组件的渲染:(this.props.children

    路由:

                

                    

                

    组件:(Center

    render(){

            return (

              

                

    这里是中心也

                {this.props.children}

              

            )

       }

    多组件的渲染


    路由:

                

                   

                

    组件:

    render(){

    const { left, right } = this.props

            return (

              

                

    这里是中心也

                {left}-{right}

              

            )

       }

    异步组件(组件的懒加载)

    单组件路由的定义:(getComponent()方法使用)

    注:这里采用的是webpackrequire.ensure()进行的组件懒加载,接受三个参数,第一个参数为加载当前模块时的依赖,第二个参数为加载的当前的模块的回掉函数,第三个参数为加载完毕后模块的名称;

    这里的getComponent函数第一个参数为当前路由的信息,第二个参数为一个回调函数,这里的回掉函数遵循node.js的回掉函数风格(回调函数的第一个参数为错误的捕捉,一般无错误,所以一般默认填入null,第二个参数为异步装载成功的组件;)


    {

                require.ensure([],(require)=>{

                   cb(null, require('./components/routerPage/list.jsx').default)

                },'List')

              }} />



    多组件路由的定义:(getComponents方法)

    {

                require.ensure([],function(require){

                   cb(null, {center:require('./components/routerPage/center.jsx').default,list:require('./components/routerPage/center.jsx').default})

                },'Center')

    js对象的方式配置路由组件的懒加载

    const routes = {

      path: '/',

      getComponent(nextState, cb) {

        require.ensure([], (require) => {

          cb(null, require('./components/app.jsx').default)

        }, 'App')

      },

      indexRoute:{

        getComponent(nextState, cb) {

          require.ensure([], (require) => {

            cb(null, require('./components/index.jsx').default)

          }, 'Index')

        },

      },

      childRoutes: [

        // require("./routes/listR.js").default

         {

            path: 'list',

            getComponent(nextState, cb) {

                require.ensure([], (require) => {

                    cb(null, require('./components/routerPage/list.jsx').default)

                }, 'List')

            }

        }

      ]

    }

    Route的钩子函数:(Route组件上书写)

    onEnter(nextState, replaceState, callback?)

    当 route 即将进入时调用。它提供了下一个路由的 state,一个函数重定向到另一个路径。this 会触发钩子去创建 route 实例。

    当 callback 作为函数的第三个参数传入时,这个钩子将是异步执行的,并且跳转会阻塞直到 callback 被调用。

    onLeave()

    当 route 即将离开时调用

    路由注入到组件的props上的属性和参数:

    history:路由的前端历史纪录和路由跳转方法

    go():

    goBack():

    goForward():

    push():

    replace()

    location:当前路由的参数信息

    state:通过在link上的state属性设置的对象值

    action:当前路由的纪录形式

    pathname:当前hash路由

    query:通过路由的传参,路径?后的路径,或者是query属性传递的

    params:通过动态路由传递的值

    routeParams:(小心有坑)

    this.props.params 是直接在组件中指定 route 的一个子集。例如,如果 route 的路径是 users/:userId 而 URL 是 /users/123/portfolios/345,那么 this.props.routeParams 会是 {userId: '123'},并且 this.props.params 会是 {userId: '123', portfolioId: 345}。

    route:当前路由的配置信息

    routes:当前路由所包含的所有路由片段

    在路由跳转前阻止路由的跳转:

    在组件内部如下引入:

    import { withRouter } from 'react-router'

    组件抛出时:

    export default withRouter(List)

    组件回调函数的注册:

    componentDidMount(){

             this.props.router.setRouteLeaveHook(

                 this.props.route,

                 this.routerWillLeave)

        }

        routerWillLeave(nextLocation) {

          // 返回 false 会继续停留当前页面,

          // 否则,返回一个字符串,会显示给用户,让其自己决定

            return '确认要离开?';

        }

    数据的请求

    constructorcomponentDidUpdate中(在进入路由或者进入路由的相应组件内部进行数据请求);

    withRouter进入目标路由或组件前,进行数据的请求


    PropTypes类型检查

    react15.5版本后,React.PropTypes已经废弃了,需要单独引入prop-types库进行验证

    import PropTypes from 'prop-types'

    class Children extends Component {

        constructor(props) {

            super(props)

        }

       render() {

            return (

                

                    

    这里是子组件

                   {this.props.name}

                

            )

        }

    }

    Children.propTypes={

        name:PropTypes.string

    }


    prop-types库可以校验的类型如下:


    import PropTypes from 'prop-types';

    MyComponent.propTypes = {

      // 你可以将属性声明为以下 JS 原生类型

      optionalArray: PropTypes.array,

      optionalBool: PropTypes.bool,

      optionalFunc: PropTypes.func,

      optionalNumber: PropTypes.number,

      optionalObject: PropTypes.object,

      optionalString: PropTypes.string,

      optionalSymbol: PropTypes.symbol,


      // 任何可被渲染的元素(包括数字、字符串、子元素或数组)。

      optionalNode: PropTypes.node,


      // 一个 React 元素

      optionalElement: PropTypes.element,


      // 你也可以声明属性为某个类的实例,这里使用 JS 的

      // instanceof 操作符实现。

      optionalMessage: PropTypes.instanceOf(Message),


      // 你也可以限制你的属性值是某个特定值之一

      optionalEnum: PropTypes.oneOf(['News', 'Photos']),


      // 限制它为列举类型之一的对象

      optionalUnion: PropTypes.oneOfType([

        PropTypes.string,

        PropTypes.number,

        PropTypes.instanceOf(Message)

      ]),


      // 一个指定元素类型的数组

      optionalArrayOf: PropTypes.arrayOf(PropTypes.number),


      // 一个指定类型的对象

      optionalObjectOf: PropTypes.objectOf(PropTypes.number),


      // 一个指定属性及其类型的对象

      optionalObjectWithShape: PropTypes.shape({

        color: PropTypes.string,

        fontSize: PropTypes.number

      }),


      // 你也可以在任何 PropTypes 属性后面加上 `isRequired`

      // 后缀,这样如果这个属性父组件没有提供时,会打印警告信息

      requiredFunc: PropTypes.func.isRequired,


      // 任意类型的数据

      requiredAny: PropTypes.any.isRequired,


      // 你也可以指定一个自定义验证器。它应该在验证失败时返回

      // 一个 Error 对象而不是 `console.warn` 或抛出异常。

      // 不过在 `oneOfType` 中它不起作用。

      customProp: function(props, propName, componentName) {

        if (!/matchme/.test(props[propName])) {

          return new Error(

            'Invalid prop `' + propName + '` supplied to' +

            ' `' + componentName + '`. Validation failed.'

          );

        }

      },


      // 不过你可以提供一个自定义的 `arrayOf` 或 `objectOf`

      // 验证器,它应该在验证失败时返回一个 Error 对象。 它被用

      // 于验证数组或对象的每个值。验证器前两个参数的第一个是数组

      // 或对象本身,第二个是它们对应的键。

      customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {

        if (!/matchme/.test(propValue[key])) {

          return new Error(

            'Invalid prop `' + propFullName + '` supplied to' +

            ' `' + componentName + '`. Validation failed.'

          );

        }

      })

    };

    你可能感兴趣的:(React)