浅扒react


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

  优秀之处:
    1、 专注视图层:(不处理理由,数据,以及逻辑的处理)
    2、 VirtualDom:只对dom更新,不对dom更新;只对dom进行必要的更新,实现的重绘的最小化;
    3、 jsx语法:
      1) 高内聚,低耦合
      2) onClick 不是原生dom中的onclick事件,这里是onClict是通过react的事件委托方式,触发挂在顶层dom节点上的一个事件处理函数(提高了性能);
      3) 可以将样式一起写入组件文件中;
      4) 关于jsx语法的说法:
       在jsx语法中可以直接写入组件,注意组件为了和普通标签区别,必须第一个字母大写;
       jsx语法是历史的进步还是倒退;(样式,结构,逻辑于一体)
    4、 活跃的生态圈:(开源项目)
    5、 组件式开发
  一、 手动搭建项目:
    1、npm init
    2、安装项目依赖
      cnpm install --save-dev babel-core babel-loader babel-preset-stage-2babel-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(还有一些依赖包可以依照需要下载)


    3、配置babelrc文件:
    {
      "presets": [
        "es2015",
        "stage-0",
        "react"
      ],
      "plugins": ["transform-runtime", "transform-react-jsx"]
    }
    4、webpack.config.js的配置文件:
      除了如下配置有更改,其他可以完全遵照vue的配置
      {
        test: /\.js|.jsx$/,
        use: [
          "babel-loader",
        ],
        exclude: /node_modules/
      },
    5、在vsCode中开发react的配置:
      安装jsx插件配置如下:

      安装React/Redux/react-router Snippets插件,可以帮助我们快速生成一定的语句;
      所有的react组件使用jsx后缀来标识;
  二、 自动化构建项目:
    1、初始化:
      全局安装:
      npm install –-global create- react- app
      初始化项目:
      create- react- app myReactApp
      启动服务:
      cd myReactApp
      npm start
    2、组件写法:

      importReact,{Component} from "react"
      importClickCount from "./ClickCount.jsx"

      class Main extends Component {
        constructor(props){
          super(props)
        }
      render(){
        return (
          <ul>
            <li><ClickCount name="first" num={1}></ClickCount></li>
            <li><ClickCount name="second" num={10}></ClickCount></li>
            <li><ClickCount name="third" num={7}></ClickCount></li>
          </ul>
        )
      }
    }
      export defaultMain
      注:对于jsx语法的解析必须引入React,虽然这里不用,但是如果不引入会因无法解析jsx而报错;组件的定义必须遵循首字母大写
    3、jsx语法使用:
      属性:
        1、属性值直接为字符串
        2、动态解析属性值
          constelement=(<imgsrc={user.avatarUrl}></img>);
          react的jsx:
          constelement=(
            <h1className="greeting">
              Hello,world!
            </h1>
          );

      用React.createElement()同样可以达到同样的效果;
        constelement=React.createElement(
          'h1',
          {className:'greeting'},
            'Hello, world!'
        );
    4、项目的分解:
      npm run eject 进行项目配置文件的弹射;
    5、react的工作方式:
      1) 从繁琐的dom处理中解脱出来,响应式,函数式编程思维;输入相同的数据,将产出相同的效果;数据更新,dom同时做出更新;
      2) Virtual Dom
      Dom:结构化文本的抽象表达式;
      虚拟dom:对dom树的抽象,不会触及浏览器,只存在于js内存的空间树形结构,每次的数据刷新,render函数的执行都会触发一个新旧虚拟dom的对比,如果无改变,则不更新,有改变,只更新相应dom结构;
  三、 元素的渲染
    a) jsx语法将元素渲染到dom中
    b) 更新元素渲染:
      React 元素都是immutable 不可变的。当元素被创建之后,你是无法改变其内容或属性的;更新界面的唯一方法就是重新挂载节点
      function tick() {
        const element = (
          <h2>{newDate().toLocaleTimeString()}.</h2>
        );
        ReactDOM.render(
          element,
          document.getElementById('root')
        );
      }
      setInterval(tick, 1000);

    c) 只会更新必要的部分(可以在谷歌开发者工具中进行dom更新的查看)
    d) 在react的jsx语法中,如果标签没有子元素,可以直接使用闭合标签;
    e) 在react的组件必须首字母进行大写,否则React.createEelement则无法查找到组件,进行编译;
    f) jsx支持标签名为表达式;,如果使用动态标签名,则需先将表达式解析赋值给一个变量;


  四、 React组件以及基本语法:
    1、 组件的设计要素:
      高内聚:把逻辑紧密相关的内容放在一个组件中;
      低耦合:不同组件之间的依赖关系要尽量弱化;尽量保持每个组件的独立性;
    2、 组件的生命周期:
      1) 装载过程:
        a) Constructor:
          初始化state;
          绑定成员函数的this环境(bind、:: )防止以解构的方式进行全局作用域进行调用;
          例:this.fn=this.fn.bind(this)或this.fn=::this.fn
        b) GetInitialState:初始化state值,必须结合React.createClass()使用,使用es6的方式,此函数无效果;

          const Test=React.createClass({
            getInitialState:function(){
              return {
                name:"zhangsan"
              }
            },
            getDefaultProps:function(){
              return {
                name:"zhangsan"//这里的zhangsan相当于默认值
              }
            }
           })

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


      class Test extends Component {
        constructor(props){
          super(props)
          this.state={data:new Date()}
        }
        render(){
          return (
            <ul>
              <li><ClickCount name="third" num={7}></ClickCount></li>
            </ul>
           )
          }
        }

      Test.defaultProps={
        return {
          name:"moren"
        }
      }


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

        render(){
          return (
            <ul>
              <li><ClickCount name="third" num={7}></ClickCount></li>
            </ul>
          )
        }

     f) ComponentDidMount:在render函数调用之后进行调用;但不是在render函数调用之后立即调用,而是当所有的dom树挂载并渲染完成后才会调用,这是因为render函数并不进行渲染,而只是返回一个jsx对象,渲染的工作由react库进行,只有当所有的组件的jsx对象组合完毕之后,react通过对比后才会渲染,所有此钩子函数是发生的所有组件的render函数都执行后才会执行;(只能在浏览器端触发)
    注:与angular中的link或者post函数有点相似,但是这里不仅指子组件,而是当前组件中的所有组件,包括兄弟组件;提供了dom操作的接口
    2) 更新过程:
      a) ComponentWillReceiveProps:传入的props的改变或者组件进行刷新(forceUpdate函数触发组件的刷新)都会触发此函数,但是通过this.setState改变的数据则不会触发此函数,
      b) ShouldComponentUpdate:react组件的钩子函数两个需要有返回值的钩子函数之一,另一个为render,此钩子函数的返回值为一个bolen值,如果为true时,则prop的改变以及state的改变都会引起组件的刷新,如果为false时,则不再进行渲染;此钩子函数接受两个参数,一个是nextProps,一个是nextState,可以将将要更新的值和此时的做对比,然后返回true和false来进行性能的校优;
      c) ComponentWillUpdate:跟componentWillMount相似
      d) Render
      e) ComponentDidUpdate:跟componentDidMount相似
    3) 卸载过程:
      ComponentWillUnmount:此钩子函数可以在组件卸载前执行,可以进行手动添加dom元素的删除,以及计时器和事件监听的移除;
  五、 React组件的数据
    组件内部数据类型:
      两种数据结构,prop和state,这两种数据的改变都会引起组件的重新渲染;
    1、 Prop:组件的外部接口,接受外部数据;跟html的属性的书写类似,但是除了接受字符串之外,还可以接受js对象,数字等的;如果组件进行数据反馈给外界,可以通过prop传入组件一个函数;
       Prop的读取:
        由class类的constructor函数接受,以及super()方法调用时的传入;
        最后的props为一个对象,键值分别为传入时的属性名;这里比较方便的是使用es6的解构赋值;
       PropTypes的检查:
        可以通过增加类的propTypes属性来定义prop规格,在constructor函数中进行如下定义:
        This.propTypes={
          caption:PropTypes.string.isRequired,
          initValue:PropTypes.number
        }
      注意:此属性不会影响组件的渲染,只是做到在开发过程中辅助开发;
    2、 State:由于组件不能改变出入的prop,所以当组件要进行自己的状态纪录时就需要用到state;
       初始化:state的初始化可以在constructor中,通过this.state进行设置,值必须为一个js对象的格式,通常将prop传入的外部值赋给state,以便后续操作;设置默认值时,可以用 ||操作符进行;
       读取和更新state
      更新使用this.setState({count:this.state.count++})方法;
      读取为:this.state.count这种方式
    3、 Prop和state的对比:
      Prop:定义外部接口;赋值在外部环境使用组件时;组件内部不能更改
      State:纪录内部状态;赋值在组件内部;在组件内部可以进行更改;

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

    2、 局部作用域(css modules的方式)
      此种方式采用的是css modules的做法,通过此做法,最后会将css文件中类名和dom中类名形成唯一的hash值,这样就不会造成类名的冲突了,使用场景,一般为组件内部的样式防止全局书写造成的类名污染;
    比如如下写法:
    app.css:
      .title {
        color: red;
      }
    jsx:
      import style from './App.css';

       export default ()=>{
        return(
          <h1 className={style.title}>
            Hello World
          </h1>
        );
        };
     最后会编译成如下代码:
      <h1 class="_3zyde4l1yATCOkgn-DBWEL">
        Hello World
      </h1>

    ._3zyde4l1yATCOkgn-DBWEL {
      color: red;
    }

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

    3、 行内样式:
      在jsx的dom上直接使用style属性进行样式的设置,样式的值为一个对象,这种方式的书写,可以支持css样式以js对象的方式进行书写,如果不想将组件的内部样式进行作用域隔离使用cssmodules的方式进行书写,则可以此种方式进行书写,可以直接在render函数中定义样式对象,也可以通过专门外部样式js文件配置样式对象,然后引入到dom进行使用,书写方式如下:
      varstyle={
        color:red;
      }
      <divstyle={style}>天气真好</div>
      注:在书写css属性时,一定要采用驼峰式写法;
  七、 事件处理
    1、 react中的事件绑定属性采用的是驼峰式写法:
      <button onClick={this.clickfn}>点击</button>
    2、 处理react使用class类定义方法时,无法自动绑定this的弊端:
       在constructor中使用bind为事件函数绑定this
      this.clickfn=this.clickfn.bind(this)
       在dom中调用函数时,先使用箭头函数绑定this,箭头函数的this是在定义时形成的
        <button onClick={()=>this.clickfn()}>点击</button>

    3、 jsx的onClick和html的onclick不同之处

       html的onclick弊端:
      注册的事件处理函数都是全局环境,污染了全局环境;
      使用onclick的dom元素,如果在dom树中删除时,必须手动的注销事件处理器,否则会造成内容泄露;

       jsx的onClick:
        挂载的每一个函数都是在组件内部,而不是全局;
        无论多少个onClick都是采用的事件委托的方式,在dom树顶层添加一个事件监听函数,此函数会根据具体组件分配具体的函数;

  八、 条件判断:
    在react的jsx语法中,如果遇到js语句使用{}进行包裹;
    1、 if语句的使用:

      render() {
        var element=null
        if(this.state.stateT){
          element= <div > stateT为true时< /div>
        }else{
          element= <div > stateT为false时< /div>
        }
      return (
        <div>
          <button onClick={this.changeFn}>切换</button>
          {element}
        </div>
      )
    }

    2、 jsx与运算符&&的结合:

      render(){
        return (
          <div>
            <button onClick={this.changeFn}>切换</button>
            {this.state.stateT&&<div > stateT为false时< /div>}
          </div>

        )
      }
    3、 三目运算符

      render(){
        return (
          <div>
            <button onClick={this.changeFn}>切换</button>
            {this.state.stateT?<div>stateT为true时</div>:<div> stateT为false时</div>}
          </div>
        )
      }
    4、 在jsx语法中,render可以返回null,表示不进行任何dom的渲染,但是钩子函数会执行;
  九、 列表和keys
    1、 基础用法:(key一般采用数据id,或者数据在数组中的索引)

      render() {
        var element=this.state.list.map((i,index)=><li key={index}>{i}</li>)
        return (
          <div>
            <button onClick={this.changeFn}>切换</button>
            {element}
          </div>
        )
      }
    注:如果后续进行数据的重新排序,则最好不要使用索引当作key值,否则,由于key值和dom的内容同时改变,则会引起全部dom节点的重绘;如果使用的是id,则只会调整dom节点的顺序,不会引起重绘dom树;(可以用上面例子演示,推荐使用id作为标识,而不是index)
    2、 key值只需要在兄弟元素之间唯一就可以,不需要是在全局唯一的

      render() {
        var element=this.state.list.map((i,index)=><li key={i}>{i}</li>)
        var element2=this.state.list.map((i,index)=><li key={i}>{i+1}</li>)
        return (
          <div>
            <button onClick={this.changeFn}>切换</button>
            {element}
            {element2}
          </div>
        )
      }
    3、 在jsx中使用map进行遍历

    render() {
      return (
        <ul>
          <button onClick={this.changeFn}>切换</button>
          {this.state.list.map((i)=><li key={i}>{i}</li>)}
        </ul>
       )
     }
  十、 表单
    在vue中,我们知道由于vue的mvvm架构,v与m之间是响应式的,可以实时同步,但是在react中不存在数据的双向数据绑定,只是负责view层的渲染,所以我们在react中取表单中的值时需要一定的方式
    1、 受控组件(采用react的单向数据流方式实现vue一样的双向数据绑定)
      changeFn(event){
        this.setState({
          name:event.target.value
        })
       }
      render() {
        return (
          <div>
            <p>表单</p>
            <label htmlFor="name">name:</label>
            <input type="text" id="name" value={this.state.name} onChange={this.changeFn}/>
            <p>{this.state.name}</p>
          </div>
        )
      }
    如果想对从input中获取到的值进行格式化时,则如下操作就可以实现:
      this.setState({
        name:event.target.value.toUpperCase()
      })
    2、 textarea标签在react中设置和读取值都采用value的方式
    3、 在react中的使用select,并实时获取其选择的值:
      render() {
        return (
          <div>
            <p>表单</p>
            <label htmlFor="name">name:</label>
            <select value={this.state.name} onChange={this.changeFn}>
            <option value="one">one</option>
            <option value="two">two</option>
            <option value="three">three</option>
            </select>
            <p>{this.state.name}</p>
          </div>
        )
      }
    4、 在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 (
          <div>
            <p>表单</p>
            <input type="checkbox" value={this.state.checkbox} onChange={this.changeFnAll} name="checkbox"/>
            <input type="text" value={this.state.text} onChange={this.changeFnAll} name="text"/>
            <p>{this.state.checkbox.toString()}</p>
            <p>{this.state.text}</p>
          </div>
        )
      }
  十一、 组件间通讯
    1、 父组件向子组件传递数据:
      a) 字符串常量的传递:
        <MyComponentmessage="hello world"/>
        <MyComponentmessage={'hello world'}/>
      b) 没有给属性传值,它默认为 true
        <MyTextBoxautocomplete/>
        不建议如下写法,容易与es6的对象简洁表示法冲突
        <MyTextBoxautocomplete={true}/>
      c) 使用扩张运算符进行属性的设置
        constprops={firstName:'Ben',lastName:'Hector'};
        <Greeting {...props} />;

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

    3、 兄弟组件间的通讯
      a) 状态提升
        对于没有直接关联关系的两个节点,就如 Child_1 与 Child_2 之间的关系,他们唯一的关联点,就是拥有相同的父组件。参考之前介绍的两种关系的通讯方式,如果我们向由 Child_1 向 Child_2 进行通讯,我们可以先通过 Child_1 向 Parent 组件进行通讯,再由 Parent 向 Child_2 组件进行通讯
      b) 观察者模式
        也就是像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) {
          returnfalse;
        }
        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);
        }
       }
      }
      exportdefault watchObj

  十二、 组合与继承
    在vue中的有一种组件特性叫内容分发,可以在父组件中自定义子组件的dom结构,在react中也提供了这么一种机制
    1、 包含关系:(在子组件通过this.props.children获取父组件中写在子组件开闭标签间的dom节点)
      父组件:
        render() {
          return (
            <div>
              <Children>
                <p>相当于vue的内容分发</p>
              </Children>
            </div>
          )
         }
      子组件:
        render() {
          return (
            <div>
              <p>这里是子组件</p>
              {this.props.children}
            </div>
          )
        }


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

      父组件:
        render() {
          return (
            var one= <span>这里为true</span>
            var two=<span>这里为false</span>
            return (
              <div>
                <Slot one={one} two={two}></Slot>
              </div>
            )

           )
          }
      子组件:
        render() {
          return(

            <div>
              <p>这里是子组件</p>
              {this.state.state?this.props.one:this.props.two}
            </div>

          )
        }

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

    (一) 基本用法:
     1、 首先我们需要导入一些组件...
      import { Router, Route, Link } from 'react-router'
     2、 配置路由信息:
       使用jsx语法
      React.render((
        <Router>
          <Route path="/" component={App}>
            <Route path="about" component={About}/>
            <Route path="inbox" component={Inbox}/>
          </Route>
        </Router>
      ), document.body)
     使用js对象进行配置
      const routes ={
        path:'/',
        component: App,
        childRoutes:[
          { path:'about', component: About },
          { path:'inbox', component: Inbox },
        ]
      }

      React.render(<Router routes={routes}/>, document.body)
    3、 获取参数
       通过动态路由片段
      <Route path="messages/:id" component={Message}/>
      可以通过如下方式进行获取id:
      this.props.params.id
       通过query字符串
      /foo?bar=baz;
      this.props.location.query.bar
    (二) 路由的配置规则
      1、 路径语法:
         :paramName – 匹配一段位于 /、? 或 # 之后的 URL。 命中的部分将被作为一个参数
         () – 在它内部的内容被认为是可选的
         * – 匹配任意字符(非贪婪的)直到命中下一个字符或者整个 URL 的末尾,并创建一个 splat 参数
          如下解释:
            // 匹配 /hello/michael 和 /hello/ryan
            <Route path="/hello/:name">
            // 匹配 /hello, /hello/michael 和 /hello/ryan
            <Route path="/hello(/:name)">
            // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg 
            <Route path="/files/*.*">
    (三) 常用路由类型:

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

    使用browserHistory如下:
      import{ browserHistory } from 'react-router'
      <Router history={browserHistory}>

    (四) 默认路由的设置:
      jsx:
        <IndexRoute component={Index}/>
      js对象:
        const routes = {
          path:'/',
          component:App,
          indexRoute:{
            component:Index
          },
          childRoutes: [
            { path:'list', component:List },
          ]
       }

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

  十四、 PropTypes类型检查
    在react的15.5版本后,React.PropTypes已经废弃了,需要单独引入prop-types库进行验证
      importPropTypes from 'prop-types'
      class Children extends Component {
        constructor(props) {
          super(props)
        }
        render() {
          return (
            <div>
              <p>这里是子组件</p>
              {this.props.name}
            </div>
          )
         }
        }
        Children.propTypes={
          name:PropTypes.string
        }

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

      importPropTypes 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])) {
              returnnewError(
                '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])) {
            returnnewError(
              'Invalid prop `' + propFullName + '` supplied to' +
              ' `' + componentName + '`. Validation failed.'
             );
            }
           })
          };

 

posted @ 2017-09-19 15:11  呆墨先生  阅读(273)  评论(0编辑  收藏  举报