react入门_2019 react入门至高阶实战,含react hooks - CSDN
  • react 之零基础入门

    2019-07-11 10:13:20
    付出,不一定会有收获;不付出,却一定不会有收获,...import React from "react" import {Component) from 'react' class Comp1 extends Component{ constructor(..args){ super(..args) } render(){ ...

    付出,不一定会有收获;不付出,却一定不会有收获,不要奢望出现奇迹

    react 组件写法非常简单

    import React from "react"
    import {Component) from 'react'
    
    class Comp1 extends Component{
    	
    		constructor(..args){
    			super(..args)
    		}
    
    		render(){
    			return(
    				<div></div>
    			);
    		}
    }
    
    export default Comp1;
    

     以上就是jsx 写法,顾名思义就是js + xml ,

    其中render 方法返回值,就是jsx 写法,我的理解就是写html 无非, class 变成className for 变成htmlFor 本质没啥不通

    感觉就是在写js ,写多了,也就会了!

    ————————————————————————————————

    组件的引用也非常简单,

    引入使用,就行了

     

    比我们的vue 少了一部,就是注册,vue中还要在component 中注册!

     

    ————————————————————————————————————————————

     

     

    以上都不重要,都是细节小知识点,随便找个教程都能很轻松的学会,这也是现在社会的好处,资源到处都有,就像我一样

    基本上啥都有,所以各位看客,需要任何虚拟资料都可以加我qq 1981389505 去免费获取所要的资料,

    因为我有一套爬虫系统支撑,不扯了,我们继续

    ————————————————————————————————————————————

    下面是 ,两个重点,就是  redux (全局 的状态管理) ---

    react于VUE类比
    功能 react vue
    状态管理  redux vuex
    路由 react-router-dom vue-router

     

    我们无论去使用那个组件技术,上面的 状态管理和路由都必须拿下,要不然,你基础都不会也跑不起来嘛

    所以不要着急,我们一点点前行!

     

    下面就是redux使用!

    我们先画一个整体的流程图:

     

    上面是我用画图软件画的,是有点Low,凑合看吧!

     

    
    
    import {createStore} from 'redux';
    
    
    // 处理请求的回调方法,我感觉很开心,因为一次性就把redux 的写法写正确了,可见我的js 水平很高
    function reducer1(state,action){
    	if(!state){
    		state = {
    			name:'xiaoming',
    			age:28
    		}
    	}
    
    	const type = action.type;
    	switch(type){
    		case "show":
    		return {
    			...state,
    			name:action.param
    		}
    		break;
    	}
    	return state;
    }
    
    const store = createStore(reducer1);
    
    export default store;

     

     

    import React from 'react';
    import ReactDOM from 'react-dom';
    
    import App from './App';
    
    import store from './store'
    import {Provider} from "react-redux"
    
    ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
    

     

    以上两文件,第一个文件,定义的就是全局的状态管理器

    第一个文件包含了,全局的状态管理函数!

     

    全局数据放state 中, 对数据的操作,都交给 上面的switch 中去处理!

    第二个文件主要时<Provider/> 谁被它包裹,谁就拥有了连接全局资源的权利,谁就用于了数据,和对数据处理函数!

     

    App.js

    导出的时候,这么写就行

    数据都在state 中了,

    对数据的处理函数,你可以自己写,上面的show 方法就是一个action

    调用

    最终会到了reducer 函数中

    根据action 的类型处理对应的逻辑!

    好,大概就是组件连接全局状态器

     

    发送action ,一个大JSON就是一个action ,然后reducer 函数,根据action。类型去处理对应的数据!

     

    redux 就略讲到这里,没基础的肯定看不懂这篇,只有看视频了!

    建议去看:

    http://www.itjiaocheng.com/youzhi/25805.html

    看第六期就行了,里面讲的很清楚!(标注不是做广告)

    因为我所学的都是从石川那里学的,很清晰!

    这篇先写到这里,下一个就是react 的路由,我觉得有必要去搞清楚

    基本写法, 嵌套写法,接受参数??

    我们放到下一篇

    再次一个格言: 

    每个人都会累,没人能为你承担所有悲伤,人总有一段时间要学会自己长大

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 学习React不是一蹴而就的事情,入门似乎也没那么简单。但一切都是值得的。今天给大家带来一个详细的React的实例,实例并不难,但对于初学者而言,足够认清React的思考和编写过程。认真完成这个实例的每一个细节会让...

    学习React不是一蹴而就的事情,入门似乎也没那么简单。但一切都是值得的。

    今天给大家带来一个详细的React的实例,实例并不难,但对于初学者而言,足够认清React的思考和编写过程。认真完成这个实例的每一个细节会让你受益匪浅。接下来我们开始吧!

    代码下载

    预览

    首先说明一下,本例究竟做了什么。本文实现了一个单页面人员管理系统的前台应用。包括以下功能:

    • 人员基本信息列表;
    • 人员的录入及删除;
    • 人员详细信息的查看;
    • 人员信息的编辑;
    • 根据人员身份进行筛选;
    • 根据人员某些属性进行排序;
    • 根据人姓名、年龄、身份、性别等关键字进行人员搜索。

    页面预览如下:

    图1

    图2

    为了更好地学习,请先到这里去感受一下:

    人员管理系统

    代码下载

    本文构建React组件的时候,使用了es6的语法,最终用webpack打包。最好有相关基础,我会在相关的地方进行言简意赅的说明。

    第一步:划分UI Component

    React is all about modular, composable components.

    React是模块化、组件化的。我们这里第一步要做的就是将应用划分成各个组件。我在图一、图二的基础上圈出了我们即将实现的各个组件。结果如图三、图四所示:

    图3

    图4

    每个圈出的组件功能如下,这是本应用的框架,请大家务必看清楚,其中斜体字是各个组件的名称:

    • ManageSystem 图三最外层的红色方框,这是管理模块的最外层容器,容纳整个应用;
    • StaffHeader 图三最上层蓝色方框,该模块接收用户操作的输入,包括关键字搜索输入、筛选条件以及排序方式;
    • StaffItemPanel 图三中间蓝色方框,该模块用于展示所有基于用户操作(关键字搜索、筛选、排序)结果的条目;
    • StaffFooter 图三最下层蓝色方框,该模块用于新人员的添加;
    • StaffItem 图三内层的红色方框,该模块用于展示一条人员的基本信息,包括删除和详情操作的按钮;
    • StaffDetail 图四的红色方框,每当点击StaffItem的’详情’后会显示该条目的详细信息。该模块用于展示人员的详细信息,兼有人员信息编辑的功能。

    为了更清楚地展示框架结构:

    ManageSystem
    
        StaffHeader
    
        StaffItemPanel
    
            StaffItem
            StaffItem
            StaffItem...
    
        StaffFooter
    
        StaffDetail(只在点击某条目的详情后展示)
    

    第二步:构建静态版的React应用

    在第一步中我们已经划分了各个组件,也说明了各个组件的职责。接下来我们分步完成我们的应用,首先我们做一个静态版的React,只用于render UI组件,但并不包含任何交互。

    这个步骤我们只需要参照图一、图二去做就好了,绝大部分工作基本上就是使用JSX按部就班地写html代码。这个过程不需要太多思考。每个组件中都仅仅只包含一个render()方法。

    需要注意的是,静态版的应用,数据由父组件通过props属性向下传递,state属性是用不到的,记住,state仅仅为动态交互而生。

    本应用的组件相对较多,我们不妨采用bottom-up的方式,从子组件开始。

    好了,我们开始吧。

    StaffHeader

    首先以StaffHeader为例,创建一个StaffHeader.js文件。如下:

    
    import React from 'react';
    export default class StaffHeader extends React.Component{
    
        render(){
            return (
              <div>
                  <h3 style={{'text-align':'center'}}>人员管理系统</h3>
                  <table className="optHeader">
                    <tbody>
                      <tr>
                        <td className="headerTd"><input type='text' placeholder='Search...' /></td>
                        <td className="headerTd">
                            <label for='idSelect'>人员筛选</label>
                            <select id='idSelect'>
                                <option value='0'>全部</option>
                                <option value='1'>主任</option>
                                <option value='2'>老师</option>
                                <option value='3'>学生</option>
                                <option value='4'>实习</option>
                            </select>
                        </td>
                        <td>
                            <label for='orderSelect'>排列方式</label>
                            <select id='orderSelect'>
                                <option value='0'>身份</option>
                                <option value='1'>年龄升</option>
                                <option value='2'>年龄降</option>
                            </select>
                        </td>
                      </tr>
                    </tbody>
                  </table>
              </div>
            );
        }
    }

    该组件主要用于提供搜索框,人员筛选下拉框以及排列方式下拉框。没错,我们首先就是要搭建一个静态版的React。呈现的样子参考图三最上方的蓝色框。当然,为了实现最终的样式,需要css的配合,css不是本文的关注点,本应用的css也十分简单,自行查看源代码。

    StaffItem

    StaffItem是每个具体人员的基本信息组件,用于展示人员的基本信息并接收用户的删除和点击详情的操作。新建一个StaffItem.js(该组件在StaffItemPanel中被引用):

    
    import React from 'react';
    export default class StaffItem extends React.Component{
    
        render(){
            return (
                  <tr
                    style={{'cursor': 'pointer'}}
                  >
                    <td className='itemTd'>{this.props.item.info.name}</td>
                    <td className='itemTd'>{this.props.item.info.age}</td>
                    <td className='itemTd'>{this.props.item.info.id}</td>
                    <td className='itemTd'>{this.props.item.info.sex}</td>
                    <td className='itemTd'>
                        <a className="itemBtn">删除</a>
                        <a className="itemBtn">详情</a>
                    </td>
                  </tr>
            );
        }
    }

    StaffItemPanel

    接下来是StaffItemPanel,该组件仅用于展示由父组件传入的各个人员条目,新建一个StaffItemPanel.js文件:

    
    import React from 'react';
    import StaffItem from './StaffItem.js';
    export default class StaffItemPanel extends React.Component{
    
        render(){
            let items = [];
    
            if(this.props.items.length == 0) {
                items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);
            }else {
                this.props.items.forEach(item => {
                    items.push(<StaffItem key={item.key} item={item}/>);
                });
            }
    
            return (
              <table className='itemPanel'>
                <thead>
                    <th className='itemTd'>姓名</th>
                    <th className='itemTd'>年龄</th>
                    <th className='itemTd'>身份</th>
                    <th className='itemTd'>性别</th>
                    <th className='itemTd'>操作</th>
                </thead>
                <tbody>{items}</tbody>
              </table>
            );
        }
    }

    该组件的功能相对简单,其中

    
            if(this.props.items.length == 0) {
                items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);
            }else {
                this.props.items.forEach(item => {
                    items.push(<StaffItem key={item.key} item={item} />);
                });
            }

    是为了在暂无条目的时候给出相应的提示,如下图:

    图5

    StaffFooter

    StaffFooter组件的功能是添加新人员,新建StaffFooter.js文件:

    
    import React from 'react';
    export default class StaffFooter extends React.Component{
    
        render(){
            return (
              <div>
                <h4 style={{'text-align':'center'}}>人员新增</h4>
                <hr/>
                <form ref='addForm' className="addForm">
                    <div>
                      <label for='staffAddName' style={{'display': 'block'}}>姓名</label>
                      <input ref='addName' id='staffAddName' type='text' placeholder='Your Name'/>
                    </div>
                    <div>
                      <label for='staffAddAge' style={{'display': 'block'}}>年龄</label>
                      <input ref='addAge' id='staffAddAge' type='text' placeholder='Your Age(0-150)'/>
                    </div>
                    <div>
                      <label for='staffAddSex' style={{'display': 'block'}}>性别</label>
                      <select ref='addSex' id='staffAddSex'>
                        <option value='男'></option>
                        <option value='女'></option>
                      </select>
                    </div>
                    <div>
                      <label for='staffAddId' style={{'display': 'block'}}>身份</label>
                      <select ref='addId' id='staffAddId'>
                        <option value='主任'>主任</option>
                        <option value='老师'>老师</option>
                        <option value='学生'>学生</option>
                        <option value='实习'>实习</option>
                      </select>
                    </div>
                    <div>
                      <label for='staffAddDescrip' style={{'display': 'block'}}>个人描述</label>
                      <textarea ref='addDescrip' id='staffAddDescrip' type='text'></textarea>
                    </div>
                    <p ref="tips" className='tips' >提交成功</p>
                    <p ref='tipsUnDone' className='tips'>请录入完整的人员信息</p>
                    <p ref='tipsUnAge' className='tips'>请录入正确的年龄</p>
                    <div>
                      <button>提交</button>
                    </div>
                </form>
              </div>
            )
        }
    }

    代码看起来比较长,其实就是一个html表单,这个步骤基本都是不需要太多思考的操作,代码也没有任何理解上的难度,记住,我们现在就是要把整个框架搭起来,做一个静态版的应用!同样的,呈现出最终的样式,需要一些css,自行参考源代码。呈现的样子见图三最下面的蓝色方框。

    StaffDetail

    通常情况下,该组件是不显示的,只有当用户点击某条目的详情的时候,我用了一种动画效果将该组件’浮现出来’。方法就是在css中将该组件的z-index设置为一个很大的值,比如100,然后通过逐渐改变背景透明度的动画实现浮现的效果。目前我们只需要做一个静态版的React,尚未实现用户点击操作的交互,所以这里只需要创建以下js文件,并在css中将.overLay的display设置为none就可以了,源码中的css文件已经做好了。

    
    import React from 'react';
    export default class StaffDetail extends React.Component{
    
        render(){
          let staffDetail = this.props.staffDetail;  
          if(!staffDetail)
            return null;
    
          return (
              <div className="overLay">
                <h4 style={{'text-align':'center'}}>点击'完成'保存修改,点击'关闭'放弃未保存修改并退出.</h4>
                <hr/>
                <table ref="editTabel">
                  <tbody>
                    <tr>
                      <th>姓名</th>
                      <td><input id='staffEditName' type="text" defaultValue={staffDetail.info.name}></input></td>
                    </tr>
                    <tr>
                      <th>年龄</th>
                      <td><input id='staffEditAge' type="text" defaultValue={staffDetail.info.age}></input></td>
                    </tr>
                    <tr>
                      <th>性别</th>
                      <td>
                        <select ref='selSex' id='staffEditSex'>
                          <option value="男"></option>
                          <option value="女"></option>
                        </select>
                      </td>
                    </tr>
                    <tr>
                      <th>身份</th>
                      <td>
                        <select ref="selId" id='staffEditId'>
                          <option value="主任">主任</option>
                          <option value="老师">老师</option>
                          <option value="学生">学生</option>
                          <option value="实习">实习</option>
                        </select>
                      </td>
                    </tr>
                    <tr>
                      <th>个人描述</th>
                      <td><textarea id='staffEditDescrip' type="text" defaultValue={staffDetail.info.descrip}></textarea></td>
                    </tr>
                  </tbody>
                </table>
                <p ref='Dtips' className='tips'>修改成功</p>
                <p ref='DtipsUnDone' className='tips'>请录入完整的人员信息</p>
                <p ref='DtipsUnAge' className='tips'>请录入正确的年龄</p>
                <button>完成</button>
                <button>关闭</button>
              </div>
          );
        }
    }

    和staffFooter类似,这里主要就是一个表单。

    ManageSystem

    子组件都已经做好了,接下来就是最外层的容器了。按部就班,新建一个ManageSystem.js:

    
    import React from 'react';
    import StaffHeader from './StaffHeader.js';
    import StaffItemPanel from './StaffItemPanel.js';
    import StaffFooter from './StaffFooter.js';
    import StaffDetail from './StaffDetail.js';
    
    var rawData = [{ info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 20, name: '张三', id: '主任'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 21, name: '赵静', id: '学生'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 22, name: '王二麻', id: '学生'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '女', age: 24, name: '李晓婷', id: '实习'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 23, name: '张春田', id: '实习'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 22, name: '刘建国', id: '学生'}},
                   { info: {descrip:'我是一匹来自远方的狼。', sex: '男', age: 24, name: '张八', id: '主任'}},
                   { info: {descrip:'我是一匹来自远方的狗。', sex: '男', age: 35, name: '李四', id: '老师'}},
                   { info: {descrip:'我是一匹来自远方的猪。', sex: '男', age: 42, name: '王五', id: '学生'}},
                   { info: {descrip:'我是一匹来自远方的牛。', sex: '男', age: 50, name: '赵六', id: '实习'}},
                   { info: {descrip:'我是一匹来自远方的马。', sex: '男', age: 60, name: '孙七', id: '实习'}}];
    
    class App extends React.Component {
    
        render(){
          return (
            <div>
              <StaffHeader/>
              <StaffItemPanel items={rawData} />
              <StaffFooter/>
              <StaffDetail/>
            </div>
          );
        }
    }
    
    React.render(<App />, document.getElementById('app'));

    以上代码中rawData是演示数据,生产中的数据应该从数据库获得,这里为了简便,直接生成了11条演示用的数据。

    第三步:编译并打包

    在第二步中,我们已经生成了各个component以及subcomponent。主要的任务已经完成了,这一步是做什么的呢?

    简单地说,上文中我们编写React Component的过程中,使用了es6和JSX的语法。(特别值得一提的是es6的Module,终于从语言规格上让Javascript拥有了模块功能。如今js渐入佳境,学习es6是十分重要且值得的!)但这些目前是不能被浏览器直接支持的。所以在使用之前,要先经过’编译’,这个过程我们是使用Babel完成的。

    关于Babel,正如其官网所言–Babel is a Javascript compiler.本应用中,它帮我们完成了es6以及JSX的编译。只不过在本例中babel是以webpack的loader的方式出现的。

    关于webpack这里也不多言了–webpack is a module bundler.请大家自己查阅相关资料。

    安装依赖项

    在这里,首先执行以下命令,安装开发依赖:

    npm install
    

    该命令会自动读取当前目录下的package.json文件,并自行安装其中的依赖项。文件内容如下:

    {
      "name": "StaffManage",
      "version": "1.0.0",
      "description": "",
      "main": "",
      "scripts": {
        "start": "webpack"
      },
      "author": "WYH",
      "license": "ISC",
      "devDependencies": {
        "babel-core": "^6.14.0",
        "babel-loader": "^6.2.5",
        "babel-preset-es2015": "^6.14.0",
        "babel-preset-react": "^6.11.1",
        "webpack": "^1.13.2"
      }
    }
    

    更具体地说,其中的开发依赖项就是

      "devDependencies": {
        "babel-core": "^6.14.0",
        "babel-loader": "^6.2.5",
        "babel-preset-es2015": "^6.14.0",
        "babel-preset-react": "^6.11.1",
        "webpack": "^1.13.2"
      }
    

    编译打包

    安装开发依赖项后,接下来就是使用webpack打包了,webpack的loader在解析文件的时候会自动使用babel对文件进行编译。配置文件如下:

    module.exports = {
        entry: __dirname + '/src/ManageSystem.js',
        output: {
            path: __dirname + '/build',
            filename: "bundle.js"
        },
        externals: {
            'react': 'React'
        },
        devtool: 'eval-source-map',  //生成source file
        module: {
            loaders: [
              {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel',
                query: {
                  presets: ['es2015', 'react']
                }
              }
            ]
        }
    };
    

    将第二步中的所有组件都放到当前目录下的src目录中,目录结构可以参考源代码,然后执行以下命令:

    npm start
    

    该命令也是在package.json中指定的。

    "scripts": {
      "start": "webpack"
    }
    

    好了,在build目录下应该已经生成bundle.js文件,这就是我们打包好的文件,我们只需要在html中引用它就行了。

    在当前目录下生成html文件如下:

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="utf-8">
        <title>人员管理</title>
        <link href="build/style.css" rel="stylesheet" />
    
      </head>
      <body>
          <div id="app">
          </div>
    
          <script src="http://cdn.bootcss.com/react/0.13.3/react.min.js"></script>
          <script src="build/bundle.js"></script>
      </body>
    </html>

    接下来在浏览器中打开index.html看看吧,静态版的React已经生成了,只是还没有动态交互而已。至此,已经完成了构建静态版的React的工作,大框架已经建立,接下来我们让它动起来!

    第四步:添加STAFF类

    本文应用涉及的功能有排序,筛选、新增、删除、修改以及关键字搜索等。功能较多,业务逻辑有些复杂。为了让React集中精力完成view层的事情,我们这里新建一个STAFF类来完成业务逻辑。

    Javascript中,类的实现是基于其原型继承机制的。但在es6中,提供了更接近传统面向对象语言的写法,引入了类(class)的概念。我们可以通过class关键字来定义类。实际上,es6的class只是一个语法糖(syntax sugar),它的绝大部分功能,es5均可以做到。而引入的class写法,是为了让对象的写法更加清晰、更加具有面向对象的感觉。

    接下来我们新建一个STAFF.js文件:

    
    class staffItem {
        constructor(item){
            this.info = {};
            this.info.name = item.name;
            this.info.age = item.age || 0;
            this.info.sex = item.sex;
            this.info.id = item.id;
            this.info.descrip = item.descrip || '';
            this.key = ++staffItem.key;
        }
    }
    staffItem.key = 0;
    
    export default class STAFF {
    
        constructor(){
            this.allStaff = [
                new staffItem(STAFF.rawData[0]),
                new staffItem(STAFF.rawData[1]),
                new staffItem(STAFF.rawData[2]),
                new staffItem(STAFF.rawData[3]),
                new staffItem(STAFF.rawData[4]),
                new staffItem(STAFF.rawData[5]),
                new staffItem(STAFF.rawData[6]),
                new staffItem(STAFF.rawData[7]),
                new staffItem(STAFF.rawData[8]),
                new staffItem(STAFF.rawData[9]),
                new staffItem(STAFF.rawData[10])
            ];
            this.staff = this.allStaff;
        }
    }
    
    STAFF.rawData = [{ descrip:'我是一匹来自远方的狼。', sex: '男', age: 20, name: '张三', id: '主任'},
                     { descrip:'我是一匹来自远方的狼。', sex: '女', age: 21, name: '赵静', id: '学生'},
                     { descrip:'我是一匹来自远方的狼。', sex: '女', age: 22, name: '王二麻', id: '学生'},
                     { descrip:'我是一匹来自远方的狼。', sex: '女', age: 24, name: '李晓婷', id: '实习'},
                     { descrip:'我是一匹来自远方的狼。', sex: '男', age: 23, name: '张春田', id: '实习'},
                     { descrip:'我是一匹来自远方的狼。', sex: '男', age: 22, name: '刘建国', id: '学生'},
                     { descrip:'我是一匹来自远方的狼。', sex: '男', age: 24, name: '张八', id: '主任'},
                     { descrip:'我是一匹来自远方的狗。', sex: '男', age: 35, name: '李四', id: '老师'},
                     { descrip:'我是一匹来自远方的猪。', sex: '男', age: 42, name: '王五', id: '学生'},
                     { descrip:'我是一匹来自远方的牛。', sex: '男', age: 50, name: '赵六', id: '实习'},
                     { descrip:'我是一匹来自远方的马。', sex: '男', age: 60, name: '孙七', id: '实习'}];

    在STAFF.js中我们实际上创建了2个类,为了实现更好的’封装性’,我们将每一个人员条目单独作为一个staffItem类,该对象中包含了该人员的所有信息,在本应用中包含他的姓名、年龄、性别、身份、个人描述等,实践中我们可以加入类似入职时间,福利薪酬,个人经历等信息。另外还有一个key值,它是一个类变量,这个值是唯一标识该staffItem用的。

    在第二步,我们在ManageSystem.js中伪造了一些数据,现在我们也把它搬到STAFF中。毕竟React不是存数据用的。

    在STAFF类的构造函数中,创建了2个实例变量,一个是allStaff,其中存储所有staffItem;一个是staff,它是最终需要给React展示的数据,是经过用户筛选操作、关键字搜索操作之后得到的人员数组。之所以这么设计变量也是为了后面的筛选、搜索等功能。在这里我们尚无这些操作的逻辑,直接将allStaff赋给staff即可。

    好了,接下来在ManageSystem中引入Staff.js,并初始化state:

    
    import React from 'react';
    import StaffHeader from './StaffHeader.js';
    import StaffItemPanel from './StaffItemPanel.js';
    import StaffFooter from './StaffFooter.js';
    import StaffDetail from './StaffDetail.js';
    
    import STAFF from './STAFF.js';
    
    class App extends React.Component {
    
        constructor(){
            super();
            this.state = {
                staff : new Staff
            };
        }
    
        render(){
          return (
            <div>
              <StaffHeader/>
              <StaffItemPanel items={this.state.staff.staff} />
              <StaffFooter/>
              <StaffDetail/>
            </div>
          );
        }
    }
    
    React.render(<App />, document.getElementById('app'));    

    在构造函数中,new了一个STAFF类,然后将this.state.staff.staff传入<StaffItemPanel/>的items属性。

    然后重新编译打包:

    npm start
    

    再次在浏览器打开index.html文件,虽然还是一个静态版的React,不过它已经变得更加模块化和’专一’了,结构也更加漂亮。

    第五步:完成新增人员功能

    关于state

    上文说过,state是为交互而生的。React是自上而下的单向数据流,state通常由上层组件拥有并控制,state的变化将触发建立在该state上的一系列自上而下的组件更新。注意,组件只能update它自己的state,如果下层组件的操作希望改变应用的状态,形成一个inverse data flow–反向数据流,我们需要从上层组件传入一个回调函数。关于state如何确定,可以参考官网一篇文章Thinking in React。接下来我们看人员功能添加是如何完成的。

    实现人员新增功能

    真正让React动起来,不妨从新增人员逻辑开始吧,这个功能比较纯粹,和其他业务耦合度不高。重新打开StaffFooter.js,加入部分代码:

    
    import React from 'react';
    export default class StaffFooter extends React.Component{
    
        handlerAddClick(evt){
            evt.preventDefault();
            let item = {};
            let addForm = React.findDOMNode(this.refs.addForm);
            let sex = addForm.querySelector('#staffAddSex');
            let id = addForm.querySelector('#staffAddId');
    
            item.name = addForm.querySelector('#staffAddName').value.trim();
            item.age = addForm.querySelector('#staffAddAge').value.trim();
            item.descrip = addForm.querySelector('#staffAddDescrip').value.trim();
            item.sex = sex.options[sex.selectedIndex].value;
            item.id = id.options[id.selectedIndex].value;
    
            /*
             *表单验证
             */
            if(item.name=='' || item.age=='' || item.descrip=='') {
                let tips = React.findDOMNode(this.refs.tipsUnDone);
                tips.style.display = 'block';
                setTimeout(function(){
                    tips.style.display = 'none';
                }, 1000);
                return;
            }
            //非负整数
            let numReg = /^\d+$/;
            if(!numReg.test(item.age) || parseInt(item.age)>150) {
                let tips = React.findDOMNode(this.refs.tipsUnAge);
                tips.style.display = 'block';
                setTimeout(function(){
                    tips.style.display = 'none';
                }, 1000);
                return;
            }
    
            this.props.addStaffItem(item);
            addForm.reset();
    
            //此处应在返回添加成功信息后确认
            let tips = React.findDOMNode(this.refs.tips);
            tips.style.display = 'block';
            setTimeout(function(){
                tips.style.display = 'none';
            }, 1000);
        }
    
        render(){
            return (
              <div>
                <h4 style={{'text-align':'center'}}>人员新增</h4>
                <hr/>
                <form ref='addForm' className="addForm">
                    <div>
                      <label for='staffAddName' style={{'display': 'block'}}>姓名</label>
                      <input ref='addName' id='staffAddName' type='text' placeholder='Your Name'/>
                    </div>
                    <div>
                      <label for='staffAddAge' style={{'display': 'block'}}>年龄</label>
                      <input ref='addAge' id='staffAddAge' type='text' placeholder='Your Age(0-150)'/>
                    </div>
                    <div>
                      <label for='staffAddSex' style={{'display': 'block'}}>性别</label>
                      <select ref='addSex' id='staffAddSex'>
                        <option value='男'></option>
                        <option value='女'></option>
                      </select>
                    </div>
                    <div>
                      <label for='staffAddId' style={{'display': 'block'}}>身份</label>
                      <select ref='addId' id='staffAddId'>
                        <option value='主任'>主任</option>
                        <option value='老师'>老师</option>
                        <option value='学生'>学生</option>
                        <option value='实习'>实习</option>
                      </select>
                    </div>
                    <div>
                      <label for='staffAddDescrip' style={{'display': 'block'}}>个人描述</label>
                      <textarea ref='addDescrip' id='staffAddDescrip' type='text'></textarea>
                    </div>
                    <p ref="tips" className='tips' >提交成功</p>
                    <p ref='tipsUnDone' className='tips'>请录入完整的人员信息</p>
                    <p ref='tipsUnAge' className='tips'>请录入正确的年龄</p>
                    <div>
                      <button onClick={this.handlerAddClick.bind(this)}>提交</button>
                    </div>
                </form>
              </div>
            )
        }
    }

    我们在提交的按钮上绑定了点击事件。点击提交按钮后,执行以下函数:

    handlerAddClick(evt){
        evt.preventDefault();
        let item = {};
        let addForm = React.findDOMNode(this.refs.addForm);
        let sex = addForm.querySelector('#staffAddSex');
        let id = addForm.querySelector('#staffAddId');
    
        item.name = addForm.querySelector('#staffAddName').value.trim();
        item.age = addForm.querySelector('#staffAddAge').value.trim();
        item.descrip = addForm.querySelector('#staffAddDescrip').value.trim();
        item.sex = sex.options[sex.selectedIndex].value;
        item.id = id.options[id.selectedIndex].value;
    
        /*
         *表单验证
         */
        if(item.name=='' || item.age=='' || item.descrip=='') {
            let tips = React.findDOMNode(this.refs.tipsUnDone);
            tips.style.display = 'block';
            setTimeout(function(){
                tips.style.display = 'none';
            }, 1000);
            return;
        }
        //非负整数
        let numReg = /^\d+$/;
        if(!numReg.test(item.age) || parseInt(item.age)>150) {
            let tips = React.findDOMNode(this.refs.tipsUnAge);
            tips.style.display = 'block';
            setTimeout(function(){
                tips.style.display = 'none';
            }, 1000);
            return;
        }
    
        this.props.addStaffItem(item);
        addForm.reset();
    
        //此处应在返回添加成功信息后确认
        let tips = React.findDOMNode(this.refs.tips);
        tips.style.display = 'block';
        setTimeout(function(){
            tips.style.display = 'none';
        }, 1000);
    }
    

    这里我们获取并简单处理了表单,特别注意

    this.props.addStaffItem(item);
    

    这一行代码,就是调用了ManageSystem通过prop属性传入的回调函数。在ManageSystem中加入相关代码:

    
    import React from 'react';
    import StaffHeader from './StaffHeader.js';
    import StaffItemPanel from './StaffItemPanel.js';
    import StaffFooter from './StaffFooter.js';
    import StaffDetail from './StaffDetail.js';
    
    import Staff from './STAFF.js';
    
    
    class App extends React.Component {
        constructor(){
            super();
            this.state = {
                staff : new Staff,
                staffDetail: null
            };
        }
    
        //增
        addStaffItem(item){
            this.setState({
                staff: this.state.staff.addStaffItem(item)
            });
        }
    
        render(){
          return (
            <div>
              <StaffHeader/>
              <StaffItemPanel items={this.state.staff.staff}}/>
              <StaffFooter addStaffItem={this.addStaffItem.bind(this)}/>
              <StaffDetail/>
            </div>
          );
        }
    }
    
    React.render(<App />, document.getElementById('app'));

    <StaffFooter addStaffItem={this.addStaffItem.bind(this)}/>中传入了addStaffItem方法。

    //增
    addStaffItem(item){
        this.setState({
            staff: this.state.staff.addStaffItem(item)
        });
    }
    

    中更新了自己的state。只不过具体的逻辑是在STAFF类的方法中完成的。

    STAFF.js:

    
    export default class STAFF {
    
        constructor(){
            this.allStaff = [
                new staffItem(STAFF.rawData[0]),
                new staffItem(STAFF.rawData[1]),
                new staffItem(STAFF.rawData[2]),
                new staffItem(STAFF.rawData[3]),
                new staffItem(STAFF.rawData[4]),
                new staffItem(STAFF.rawData[5]),
                new staffItem(STAFF.rawData[6]),
                new staffItem(STAFF.rawData[7]),
                new staffItem(STAFF.rawData[8]),
                new staffItem(STAFF.rawData[9]),
                new staffItem(STAFF.rawData[10])
            ];
            this.staff = this.allStaff;
        }
    
        //增
        addStaffItem(item) {
            let newItem = new staffItem(item);
            this.allStaff.push(newItem);
            this.staff = this.allStaff;
            return this;
        }
    }

    重新编译打包生成bundle.js文件:

    npm start
    

    再次在浏览器中打开index.html文件,试试我们新添加的人员添加功能吧!

    第六步:完成关键字搜索功能

    类似第五步新人员的添加,我们首先给StaffHeader中的搜索输入框绑定一个onChange事件,每当搜索内容改变时,触发该函数:

    StaffHeader.js

    
    import React from 'react';
    export default class StaffHeader extends React.Component{
    
        //search
        handlerSearch(){
            let bar = React.findDOMNode(this.refs.searchBar);
            let value = bar.value;
            this.props.searchStaff(value);
        }
    
        render(){
            return (
              <div>
                  <h3 style={{'text-align':'center'}}>人员管理系统</h3>
                  <table className="optHeader">
                    <tbody>
                      <tr>
                        <td className="headerTd"><input ref='searchBar' onChange={this.handlerSearch.bind(this)} type='text' placeholder='Search...' /></td>
                        <td className="headerTd">
                            <label for='idSelect'>人员筛选</label>
                            <select id='idSelect'>
                                <option value='0'>全部</option>
                                <option value='1'>主任</option>
                                <option value='2'>老师</option>
                                <option value='3'>学生</option>
                                <option value='4'>实习</option>
                            </select>
                        </td>
                        <td>
                            <label for='orderSelect'>排列方式</label>
                            <select id='orderSelect'>
                                <option value='0'>身份</option>
                                <option value='1'>年龄升</option>
                                <option value='2'>年龄降</option>
                            </select>
                        </td>
                      </tr>
                    </tbody>
                  </table>
              </div>
            );
        }
    }

    同样在事件处理函数中,调用了通过props属性传入的回调函数searchStaff:

    //search
    handlerSearch(){
        let bar = React.findDOMNode(this.refs.searchBar);
        let value = bar.value;
        this.props.searchStaff(value);
    }
    

    逐步完善ManageSystem以及STAFF类:

    ManageSystem.js:

    
    class App extends React.Component {
        constructor(){
            super();
            this.state = {
                staff : new Staff,
                staffDetail: null
            };
        }
    
        //增
        addStaffItem(item){
            this.setState({
                staff: this.state.staff.addStaffItem(item)
            });
        }
    
        /*
         * 搜索
         */
        searchStaff(word) {
            this.setState({
                staff: this.state.staff.searchStaff(word)
            });
        }
    
        render(){
          return (
            <div>
              <StaffHeader searchStaff={this.searchStaff.bind(this)} />
              <StaffItemPanel items={this.state.staff.staff}}/>
              <StaffFooter addStaffItem={this.addStaffItem.bind(this)}/>
              <StaffDetail/>
            </div>
          );
        }
    }

    STAFF.js

    
    export default class STAFF {
    
        constructor(){
            this.allStaff = [
                new staffItem(STAFF.rawData[0]),
                new staffItem(STAFF.rawData[1]),
                new staffItem(STAFF.rawData[2]),
                new staffItem(STAFF.rawData[3]),
                new staffItem(STAFF.rawData[4]),
                new staffItem(STAFF.rawData[5]),
                new staffItem(STAFF.rawData[6]),
                new staffItem(STAFF.rawData[7]),
                new staffItem(STAFF.rawData[8]),
                new staffItem(STAFF.rawData[9]),
                new staffItem(STAFF.rawData[10])
            ];
            this.staff = this.allStaff;
            this.word = '';  //搜索关键字
        }
    
        //增
        addStaffItem(item) {
            let newItem = new staffItem(item);
            this.allStaff.push(newItem);
            this.staff = this.allStaff;
            return this;
        }
    
        //搜索
        searchStaff(word){
            this.word = word;
            this.staff = this.allStaff;
            //在staff中搜索
            this.staff = this.staff.filter(item => {
                return item.info.name.indexOf(word)!=-1 || 
                       (item.info.age+'').indexOf(word)!=-1 || 
                       item.info.id.indexOf(word)!=-1 ||
                       item.info.sex.indexOf(word)!=-1;
            });
            return this;
        }
    }

    依据关键字的搜索功能至此也完成了。

    完成接下来的功能

    作为示例,第五步以及第六步完成了添加人员以及关键字搜索功能。随后随着功能的不断添加,最终代码的实现会有微小的调整。实现的方法大同小异,请大家对照源码,依照上面的方法逐步完整整个应用。我相信你实现了每一个细节之后,对面入门React一定会有十分大的帮助。

    展开全文
  • React 入门附带demo

    2018-09-12 10:44:40
    DEMO 1 - 最简单的react渲染 代码: &lt;html&gt; &lt;head&gt; &lt;link href="css/bootstrap.min.css" rel="stylesheet"&gt; &lt;/head&gt; &lt...

    DEMO 1 - 最简单的react渲染

    代码:

    <html>
        <head>
            <link href="css/bootstrap.min.css" rel="stylesheet">
        </head>
    
        <body>
            <h1><span class="label label-info">DEMO 1</span></h1>
            <br><br><br>
    
    
            <div class="well" id="well">
    
            </div>
    
            <script src="js/jquery.min.js"></script>
            <script src="js/react.js"></script>
            <script src="js/react-dom.js"></script>
            <script src="js/browser.min.js"></script>
    
            <script type="text/babel">
            var Text = React.createClass({
                render: function() {
                    return (
                        <div className="a">
                            大家好,我是用react渲染出来的!
                        </div>
                    );
                }
            });
    
            ReactDOM.render(
                <Text/>,
                document.getElementById('well')
            );
            </script>
        </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在浏览器中显示的效果如下

    这里写图片描述

    讲解:

    • 页面中,只有<div id='well'>这里的内容是使用react渲染出来的,代码中这里是空的,依赖下面的js进行渲染
    • 首先看下 vat Text = 这块,这里是声明一个模块,名字随意起,我们把第一个字母大写,用来区分html中原生的标签
    React.createClass({
        render: function() {
            return (
                <div className="a">
                    大家好,我是用react渲染出来的!
                </div>
            );
        }
    });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这块是创建一个模块,使用React.createClass即可创建。 
    * 其中参数有很多,但都可以省略,唯有render不可以省略,因为这是用来表述这个插件被加载后,显示的是什么样子,它的返回结果,就是加载在页面上最终的样式。

    ReactDOM.render(
       <Text/>,
        document.getElementById('well')
    );
    • 1
    • 2
    • 3
    • 4

    这段代码是用来渲染react组件额,第一个参数是组件,第二个参数是要渲染的位置。 
    * 使用<Text/>的 方式就可以实例化组件,或者写成<Text></Text>,要注意下,react中标签的闭合非常严格,任何标签的关闭与打开必须一一对应,否则会报错。 
    * 到目前为止,就完成了一次渲染,将Text组件render函数返回的内容,填充到了id=well的div中。


    DEMO 2 - 带有参数的react

    往往在使用中,文本的内容并不是写死的,而是需要被我们指定,这样组件才能更通用。下面介绍下,如何向react中传递参数。

    代码:

    <html>
        <head>
            <link href="css/bootstrap.min.css" rel="stylesheet">
        </head>
    
        <body>
            <h1><span class="label label-info">DEMO 2</span></h1>
            <br><br><br>
    
    
            <div class="well" id="well">
    
            </div>
    
            <script src="js/jquery.min.js"></script>
            <script src="js/react.js"></script>
            <script src="js/react-dom.js"></script>
            <script src="js/browser.min.js"></script>
    
            <script type="text/babel">
            var Text = React.createClass({
                render: function() {
                    return (
                        <div className="a">
                            大家好,我是用{this.props.name}渲染出来的!age={this.props.age}
                        </div>
                    );
                }
            });
    
            ReactDOM.render(
                <Text name="react" age={181}></Text>,
                document.getElementById('well')
            );
    
            </script>
        </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在浏览器中显示的效果如下

    这里写图片描述

    讲解

    • 首先,这个大体上跟第一个demo类似,唯有实例化Text时,多了参数。
    • 当我们传递参数时,写了两种方式,一种是 name="react"另一种是age={181},这两种写法是有区别的,并不仅仅因为一个是str,一个是int。如果是str这种类型,写成 name="xxx"或者name={"xxx"}都是可以的,加了{}的意思就是js中的变量,更加精确了。而后者age={181}是不可以去掉{}的,这样会引起异常,所以这里要注意下,并且建议任何类型都加上{}来确保统一。
    • 当在Text初始化时添加了参数,在组件内部,都收集在this.props中,使用时只要{this.props.name}既可以获取name对应的值,如果取得key并不存在,这里不会报错,只是取到的值是空的。当然可以在getDefaultProps中定义默认的props值,即使在没有传递参数的情况下,也能取到默认值。
    • props中的参数,在初始化传递后,便不能再修改。

    DEMO 3 - state,react的核心

    state算是react的核心了,任何页面的变化,刷新都是state的变化引起。在react中,只要调用了setState都会引起render的重新执行。下面介绍下如何通过键盘事件触发状态变化。

    代码:

    <html>
        <head>
            <link href="css/bootstrap.min.css" rel="stylesheet">
        </head>
    
        <body>
            <h1><span class="label label-info">DEMO 3</span></h1>
            <br><br><br>
    
    
            <div class="well" id="well">
    
            </div>
    
            <script src="js/jquery.min.js"></script>
            <script src="js/react.js"></script>
            <script src="js/react-dom.js"></script>
            <script src="js/browser.min.js"></script>
    
            <script type="text/babel">
            var Text = React.createClass({
                getInitialState: function() {
                    return {name: "react"};
                },
                keyUp: function(e){
                    this.setState({name: e.target.value});
                    console.log(this.state.name);
                },
                render: function() {
                    return (
                        <div className="a">
                            大家好,我是用{this.state.name}渲染出来的!
                            <input onKeyUp={this.keyUp} />
                        </div>
                    );
                }
            });
    
            ReactDOM.render(
                <Text></Text>,
                document.getElementById('well')
            );
    
            </script>
        </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在浏览器中显示的效果如下

    这里写图片描述

    讲解:

    • 这次组件中多了两个函数,getInitialStatekeyUp,其中getInitialState是react中的初始化状态的函数,类似上一节中getDefaultProps的作用。keyUp是我自定义的函数,用来响应键盘事件的。
    • 我们先看render函数,文字渲染中加了{this.state.name},这个是react内部的状态,可以理解是存储数据的k-v结构,这里的v支持的对象较多。{this.state.name}就是引用状态中的name属性,与props的区别在于,如果state中不存在这个属性,是会报错的,所以我们要在getInitialState中初始化这个状态的初始值。
    • render中还多了一个,onKeyUp是注册键盘键弹起的事件,当按键按下后弹起,就会触发onKeyUp事件,然后通过绑定的this.keyUp,将事件传递给了自己定义的keyUp函数中。
    • keyUp函数中,使用了this.setState({name: e.target.value}),setState是react中内部的函数,专门用来更新状态的,这里是讲状态中name的值变更为引起事件的value值。
    • 在react中,每次状态的变化,都会引起render函数的重新渲染,这是它自己的机制,我们无需人为处理,当键盘输入内容时,会触发状态变化,导致render重新渲染,渲染的过程会从state中取出变量,所以我们就看到了页面的内容发生了变化。
    • 我们在setState下面加了一个console,通过控制台可以发现,每次打印的值并不是当前输入的值,而是上一次输入的值,这是怎么回事呢?在setState中,这是一个异步处理的函数,并不是同步的,console在setState后立刻执行了,所以这时候状态还没有真正变更完,所以这里取到的状态仍旧是更新前的。这里要特殊注意下。如果需要在更新状态后,再执行操作怎么办呢,setState还有第二个参数,接受一个callback,我们尝试将keyUp中代码改成这样
    this.setState({name: e.target.value}, function(){
        console.log(this.state.name);
    })
    • 1
    • 2
    • 3
    • 这时候log打印出来的只就是我们期望的内容,当每次状态更新成功后,都会调用传进去的callback函数。
    • react中渲染dom有自己的优化方式,首先它在内存中构建一套虚拟的dom,每次更新前将虚拟dom与浏览器中dom对比,只讲有变化的部分进行更新,这样大大的提高了性能。或者我们可以重写函数来控制是否刷新,当然这种方式我们并不提倡。

    DEMO 4 - 网络请求触发状态变化

    上一节讲到状态变化触发render的重新渲染,这里将常用的网络请求引入,结合到状态变化中。

    代码:

    <html>
        <head>
            <link href="css/bootstrap.min.css" rel="stylesheet">
            <style>
                .div {
                    height: 100px;
                }
            </style>
        </head>
    
        <body>
            <h1><span class="label label-info">DEMO 4</span></h1>
            <br><br><br>
    
    
            <div class="well div" id="well">
    
            </div>
    
            <script src="js/jquery.min.js"></script>
            <script src="js/react.js"></script>
            <script src="js/react-dom.js"></script>
            <script src="js/browser.min.js"></script>
    
            <script type="text/babel">
            var Text = React.createClass({
                getInitialState: function() {
                    return {cur_time: 0};
                },
                request: function() {
                    $.ajax({
                        type: "GET",
                        url: "http://xxx",
                        success: function(data){
                            this.setState({cur_time: data.timestamp});
                        }.bind(this),
                        complete: function(){
                            this.setState({cur_time: Date.parse(new Date()) / 1000});
                        }.bind(this)
                    });
                },
                componentDidMount: function(){
                    setInterval(this.request, 1000);
                },
                render: function() {
                    return (
                        <div className="col-xs-12">
                            当前时间{this.state.cur_time}
                            <div className={ this.state.cur_time % 2 == 0?"hidden": "col-xs-6 alert alert-success"}>
                                <span>最后一位奇数</span>
                            </div>
                            <div className={ this.state.cur_time % 2 != 0?"hidden": "col-xs-6 alert alert-danger"}>
                                <span>最后一位偶数</span>
                            </div>
                        </div>
                    );
                }
            });
    
            ReactDOM.render(
                <Text></Text>,
                document.getElementById('well')
            );
    
            </script>
        </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在浏览器中显示的效果如下

    这里写图片描述
    这里写图片描述

    讲解:

    • 这个例子中,页面每秒会请求一次网络,将请求到的数据中时间戳更新到状态中。但是这个例子中实际上并没有使用服务返回的时间戳,因为我在公司使用测试网的接口拿数据,但是开放给大家要换一个公网能拿到时间戳的api,简单的找了下没找到,也不想用公司的接口试,所以算是mock了下~,在complete中每次都取浏览器时间来更新。
    • 仍旧是先看代码,相比于上一个例子,这里多了两个函数requestcomponentDidMount,其中request是请求网络的函数,componentDidMount是react内部的函数,也是react生命周期的一部分,它会在render第一次渲染前执行,而且只会执行一次。
    • 先看request,一个普通的ajax请求,在success回调中,假设服务器返回的json为{“timestamp”: 1467425645},那data.timestamp就取得是1467425645,然后将值赋给state中的cur_time属性。这时状态发生了变化,render函数会重新渲染。当然例子中success不会被访问到,因为那个url根本不存在,所以我在complete回调中来写了一个状态变化,模拟success成功。
    • 为什么success回调函数最后会加一个bind(this)?因为这个函数已经不是react内部的函数了,它是一个外部函数,它里面的this并不是react组件中的this,所以要将外部函数绑定到react中,并能使用react内部的方法,例如setState,就要在函数最后bind(this),这样就完成了绑定。
    • 再看下componentDidMount函数,这个函数在render渲染前会执行,里面的代码也很简单,增加了一个定时器,1秒钟执行一次request。
    • 这里应该在加一个回调,就是定时器在初始化时创建,却没有对应的销毁,所以在组件销毁的时候,应该在这个生命周期中销毁定时器。

    DEMO 5 - 组件的嵌套使用

    在封装react时,我们往往按照最小单位封装,例如封装一个通用的div,一个通用的span,或者一个通用的table等,所以各自组件对应的方法都会随着组件封装起来,例如div有自己的方法可以更改背景色,span可以有自己的方法更改字体大小,或者table有自己的方法来更新table的内容等~ 这里我们用一个div相互嵌套的例子来查看父子组件如何相互嵌套及调用各自的方法。在下面的例子中,父组件与子组件都有一个方法,来改变自身的背景色,我们实现父子组件相互调用对方的方法,来改变对方的背景色。

    代码:

    <html>
        <head>
            <link href="css/bootstrap.min.css" rel="stylesheet">
            <style>
                .child {
                    border-color: black;
                    border: 1px solid;
                    height: 200px;
                }
                .parent {
                    height: 400px;
                    border: 3px solid;
                }
            </style>
        </head>
    
        <body>
            <h1><span class="label label-info">DEMO 5</span></h1>
            <br><br><br>
    
    
            <div id="well">
    
            </div>
    
            <script src="js/jquery.min.js"></script>
            <script src="js/react.js"></script>
            <script src="js/react-dom.js"></script>
            <script src="js/browser.min.js"></script>
    
            <script type="text/babel">
            var Child = React.createClass({
                getInitialState: function() {
                    return {color: ""};
                },
                changeColor: function(e) {
                    this.setState({color: e.target.getAttribute("data-color")});
                },
                render: function() {
                    return (
                        <div style={{backgroundColor: this.state.color}} className="col-xs-5 col-xs-offset-1 child">
                            <br/>
                            <ul className="list-inline">
                                <li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.props.parentChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.props.parentChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.props.parentChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.props.parentChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.props.parentChangeColor}>&nbsp;</a></li>
                            </ul>
                        </div>
                    );
                }
            });
    
            var Parent = React.createClass({
                getInitialState: function() {
                    return {color: ""};
                },
                changeColor: function(e) {
                    this.setState({color: e.target.getAttribute("data-color")});
                },
                child1ChangeColor: function(e) {
                    this.refs["child1"].changeColor(e);
                },
                child2ChangeColor: function(e) {
                    this.refs["child2"].changeColor(e);
                },
                render: function() {
                    return (
                        <div style={{backgroundColor: this.state.color}} className="col-xs-10 col-xs-offset-1 parent">
                            <br/>
                            <ul className="list-inline">
                                <li>对应第一个child</li>
                                <li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.child1ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.child1ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.child1ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.child1ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.child1ChangeColor}>&nbsp;</a></li>
                            </ul>
                            <ul className="list-inline">
                                <li>对应第二个child</li>
                                <li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.child2ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.child2ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.child2ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.child2ChangeColor}>&nbsp;</a></li>
                                <li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.child2ChangeColor}>&nbsp;</a></li>
                            </ul>
                            <hr/>
    
                            <Child ref="child1" parentChangeColor={this.changeColor} />
                            <Child ref="child2" parentChangeColor={this.changeColor} />
                        </div>
                    );
                }
            });
    
    
            ReactDOM.render(
                <Parent/>,
                document.getElementById('well')
            );
    
            </script>
        </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    在浏览器中显示的效果如下

    这里写图片描述

    讲解:

    • 首先说下,刚打开页面并不是这样的,背景都是白色的。这里的截图是点击各个按钮后变色的样子。
    • 在这个例子中,蓝色的div是一个父组件,它里面包含了两个子组件,分别是红色和橙色,这两个子组件实际上是一模一样的。我们先看下父组件如何调用子组件。
    • 代码中,子组件里面定义了changeColor函数,用来接收onClick事件,并将点击的按钮的data-color属性值作为色值,更改到state中的color属性中,然后触发render来更新背景色。在父组件调用子组件时,我们写了,里面的ref=”child1”就是react中提供的一个属性标签,它与普通的props不同,这里写上ref=”xxx”后,在父组件中,使用this.refs[“child1”]就可以引用对应的子组件,当然这里的ref的值是可以随意定义,只要不重复就好。这样就可以实现组组件引用子组件,然后直接调用里面的方法就好,例如child1ChangeColor中就有this.refs["child1"].changeColor(e);的使用。连起来说下逻辑,在点击父组件中第一列中的按钮后,触发onClick事件,然后onClick事件后,传递到child1ChangeColor后,将事件传递进入,然后再次传递给子组件的changeColor中,因为子组件的changeColor是更改子组件自身的state,所以这时候子组件再次渲染,于是改变了颜色。这就是父组件调用子组件的逻辑。
    • 再说下子组件何如调用父组件的方法,父组件自身也有一个changeColor函数,用来改变自身的背景色。当父组件调用子组件时,,通过props,也就是第二个例子中讲的那样,通过参数的方式传递给子组件,这样子组件中就可以使用this.props.parentChangeColor,来把子组件的onClick事件传递给父组件的changeColor方法中,来改变父组件的背景色。这就是子组件调用父组件函数的方法。
    • 还有一种情况,就是一个父组件下有多个子组件,但是子组件中并没有直接的关系,这时候如果一个子组件调用另一个子组件的方法,就得通过他们共同的父组件来作为中转,在父组件中增加函数来作为中转的函数,来实现子组件间的调用。
    展开全文
  • React 入门实例教程

    2019-03-20 11:03:55
    现在最热门的前端框架,毫无疑问是ReactReact 起源于 Facebook 的内部项目,因为该公司对市场上所有JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram的网站。做出来以后,发现这套东西很好...

    现在最热门的前端框架,毫无疑问是 React 。

    React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

    由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

    这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机。

    既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。

     

    零、安装

    React 的安装包,可以到官网下载。

     

    一、HTML 模板

    使用 React 的网页源码,结构大致如下。

    
    <!DOCTYPE html>
    <html>
      <head>
        <script src="../build/react.js"></script>
        <script src="../build/react-dom.js"></script>
        <script src="../build/browser.min.js"></script>
      </head>
      <body>
        <div id="example"></div>
        <script type="text/babel">
          // ** Our code goes here! **
        </script>
      </body>
    </html>
    

    上面代码有两个地方需要注意。首先,最后一个 <script> 标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。

    其次,上面代码一共用了三个库: react.js 、react-dom.js 和 Browser.js ,它们必须首先加载。其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。

    
    $ babel src --out-dir build
    

    上面命令可以将 src 子目录的 js 文件进行语法转换,转码后的文件全部放在 build 子目录。

    二、ReactDOM.render()

    ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

    
    ReactDOM.render(
      <h1>Hello, world!</h1>,
      document.getElementById('example')
    );
    

    上面代码将一个 h1 标题,插入 example 节点,运行结果如下。

    三、JSX 语法

    上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。

    
    var names = ['Alice', 'Emily', 'Kate'];
    
    ReactDOM.render(
      <div>
      {
        names.map(function (name) {
          return <div>Hello, {name}!</div>
        })
      }
      </div>,
      document.getElementById('example')
    );
    

    上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。上面代码的运行结果如下。

    JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员。

    
    var arr = [
      <h1>Hello world!</h1>,
      <h2>React is awesome</h2>,
    ];
    ReactDOM.render(
      <div>{arr}</div>,
      document.getElementById('example')
    );
    

    上面代码的arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板,运行结果如下。

    四、组件

    React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。

    
    var HelloMessage = React.createClass({
      render: function() {
        return <h1>Hello {this.props.name}</h1>;
      }
    });
    
    ReactDOM.render(
      <HelloMessage name="John" />,
      document.getElementById('example')
    );
    

    上面代码中,变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage /> 时,会自动生成 HelloMessage 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

    注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。

    
    var HelloMessage = React.createClass({
      render: function() {
        return <h1>
          Hello {this.props.name}
        </h1><p>
          some text
        </p>;
      }
    });
    

    上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1p

    组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloMessage name="John"> ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。上面代码的运行结果如下。

    添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor,这是因为 class 和 for 是 JavaScript 的保留字。

    五、this.props.children

    this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点。

    
    var NotesList = React.createClass({
      render: function() {
        return (
          <ol>
          {
            React.Children.map(this.props.children, function (child) {
              return <li>{child}</li>;
            })
          }
          </ol>
        );
      }
    });
    
    ReactDOM.render(
      <NotesList>
        <span>hello</span>
        <span>world</span>
      </NotesList>,
      document.body
    );
    

    上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取,运行结果如下。

    这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

    React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object

    六、PropTypes

    组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

    组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。

    
    var MyTitle = React.createClass({
      propTypes: {
        title: React.PropTypes.string.isRequired,
      },
    
      render: function() {
         return <h1> {this.props.title} </h1>;
       }
    });
    

    上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。

    
    var data = 123;
    
    ReactDOM.render(
      <MyTitle title={data} />,
      document.body
    );
    

    这样一来,title属性就通不过验证了。控制台会显示一行错误信息。

    
    Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

     

    此外,getDefaultProps 方法可以用来设置组件属性的默认值。

    
    var MyTitle = React.createClass({
      getDefaultProps : function () {
        return {
          title : 'Hello World'
        };
      },
    
      render: function() {
         return <h1> {this.props.title} </h1>;
       }
    });
    
    ReactDOM.render(
      <MyTitle />,
      document.body
    );
    

    上面代码会输出"Hello World"。

    七、获取真实的DOM节点

    组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

    但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。

    
    var MyComponent = React.createClass({
      handleClick: function() {
        this.refs.myTextInput.focus();
      },
      render: function() {
        return (
          <div>
            <input type="text" ref="myTextInput" />
            <input type="button" value="Focus the text input" onClick={this.handleClick} />
          </div>
        );
      }
    });
    
    ReactDOM.render(
      <MyComponent />,
      document.getElementById('example')
    );
    

    上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

    需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

    React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、CopyScroll 等。

    八、this.state

    组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI 。

    
    var LikeButton = React.createClass({
      getInitialState: function() {
        return {liked: false};
      },
      handleClick: function(event) {
        this.setState({liked: !this.state.liked});
      },
      render: function() {
        var text = this.state.liked ? 'like' : 'haven\'t liked';
        return (
          <p onClick={this.handleClick}>
            You {text} this. Click to toggle.
          </p>
        );
      }
    });
    
    ReactDOM.render(
      <LikeButton />,
      document.getElementById('example')
    );
    

    上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

    由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

    九、表单

    用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取。

    
    var Input = React.createClass({
      getInitialState: function() {
        return {value: 'Hello!'};
      },
      handleChange: function(event) {
        this.setState({value: event.target.value});
      },
      render: function () {
        var value = this.state.value;
        return (
          <div>
            <input type="text" value={value} onChange={this.handleChange} />
            <p>{value}</p>
          </div>
        );
      }
    });
    
    ReactDOM.render(<Input/>, document.body);
    

    上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况。

    十、组件的生命周期

    组件的生命周期分成三个状态:

    • Mounting:已插入真实 DOM
    • Updating:正在被重新渲染
    • Unmounting:已移出真实 DOM

    React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。

    • componentWillMount()
    • componentDidMount()
    • componentWillUpdate(object nextProps, object nextState)
    • componentDidUpdate(object prevProps, object prevState)
    • componentWillUnmount()

    此外,React 还提供两种特殊状态的处理函数。

    • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
    • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

    下面是一个例子。

    
    var Hello = React.createClass({
      getInitialState: function () {
        return {
          opacity: 1.0
        };
      },
    
      componentDidMount: function () {
        this.timer = setInterval(function () {
          var opacity = this.state.opacity;
          opacity -= .05;
          if (opacity < 0.1) {
            opacity = 1.0;
          }
          this.setState({
            opacity: opacity
          });
        }.bind(this), 100);
      },
    
      render: function () {
        return (
          <div style={{opacity: this.state.opacity}}>
            Hello {this.props.name}
          </div>
        );
      }
    });
    
    ReactDOM.render(
      <Hello name="world"/>,
      document.body
    );
    

    上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

    另外,组件的style属性的设置方式也值得注意,不能写成

    
    style="opacity:{this.state.opacity};"
    

    而要写成

    
    style={{opacity: this.state.opacity}}
    

    这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

    十一、Ajax

    组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI 。

    
    var UserGist = React.createClass({
      getInitialState: function() {
        return {
          username: '',
          lastGistUrl: ''
        };
      },
    
      componentDidMount: function() {
        $.get(this.props.source, function(result) {
          var lastGist = result[0];
          if (this.isMounted()) {
            this.setState({
              username: lastGist.owner.login,
              lastGistUrl: lastGist.html_url
            });
          }
        }.bind(this));
      },
    
      render: function() {
        return (
          <div>
            {this.state.username}'s last gist is
            <a href={this.state.lastGistUrl}>here</a>.
          </div>
        );
      }
    });
    
    ReactDOM.render(
      <UserGist source="https://api.github.com/users/octocat/gists" />,
      document.body
    );
    

    上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。

    我们甚至可以把一个Promise对象传入组件,请看Demo12

    
    ReactDOM.render(
      <RepoList
        promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
      />,
      document.body
    );
    

    上面代码从Github的API抓取数据,然后将Promise对象作为属性,传给RepoList组件。

    如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。

    
    var RepoList = React.createClass({
      getInitialState: function() {
        return { loading: true, error: null, data: null};
      },
    
      componentDidMount() {
        this.props.promise.then(
          value => this.setState({loading: false, data: value}),
          error => this.setState({loading: false, error: error}));
      },
    
      render: function() {
        if (this.state.loading) {
          return <span>Loading...</span>;
        }
        else if (this.state.error !== null) {
          return <span>Error: {this.state.error.message}</span>;
        }
        else {
          var repos = this.state.data.items;
          var repoList = repos.map(function (repo) {
            return (
              <li>
                <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
              </li>
            );
          });
          return (
            <main>
              <h1>Most Popular JavaScript Projects in Github</h1>
              <ol>{repoList}</ol>
            </main>
          );
        }
      }
    });
    

     

    展开全文
  • 转载...上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。 React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC
  • React入门

    2020-07-27 16:44:02
    如何获取这三个文件?...react.js npm i react --save react-dom.js npm i react-dom --save bable npm i babel-standalone --save 具体操作流程: (1)新建项目文件夹: (2)win+R 打开控制台,cd进入项目文件夹
  • web端三大框架react、vue和angular,下面是对react.js的一些总结。 一、环境搭建 1、npm搭建项目 推荐使用npm搭建项目环境,如果网速过慢,可是使用cnpm进行项目的搭建(cnpm是淘宝的npm镜像,与npm有些差异,...
  • ReactJs简介 反应最初来自Facebook的内部的广告系统项目,项目实施过程中前端开发遇到了巨大挑战,代码变得越来越臃肿且混乱不堪,难以维护于是,痛定思痛,他们决定抛开很多所谓的“最佳实践” ,重新思考前端界面...
  • react入门的资料ppt

    2020-07-25 23:33:36
    react入门的资料ppt,适合新手学习的路线,又兴趣的同学可以下载来看看,对你的以后的人生技术会有很多的助力,方便了你以后往前端方向的转型,x
  • React入门知识汇总

    2019-08-12 20:44:32
    React入门知识汇总开发环境的搭建组件(Component)组件之间通信(props与state)props   由于最近1个月在工作当中需要写前端的页面,于是用到了React,也算是入门了吧,同时组件库用到了公司内部的一些组件,...
  • 所以决定做一个react入门总结。 首先,在实现crud操作前我们需要了解,React是如何操作修改数据,先看一个简单的demon,react是如何实现数据双向绑定(我理解的数据双向绑定) 一、简单的双向绑定 ...
  • 读阮一峰的React 入门实例教程有感阮一峰的React入门实例教程其实我在一年前就读过,当时就想学习React,其实那个时候刚刚jQuery入门,啥也不懂,看得云里雾里,所以后来就没有继续研究下去了。 而这一年过来,技术...
  • react下载-react入门-react.js下载多类库js下载 React 是一个用于构建用户界面的 JAVASCRIPT 库。 React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。 React 起源于 Facebook 的内部项目,用来架设 ...
  • React入门(一)

    2018-05-23 02:10:50
    之前在进行前端工作时,也做过几个使用React框架的前端项目,最近的毕业设计也是做了一个react框架的电子商务平台,答辩完后发现个人对于React还没有做一个总结,为了准备以后的面试,在最近几天慢慢的整理出来吧。...
  • react入门

    2017-05-22 15:20:34
    react入门介绍: facebook/react react awesome-react 中文入门介绍: React 入门教程 babel可以把es6转为es5 https://kangax.github.io/compat-table/es6/查看浏览器对es6的支持情况使用npm配置React环境 基于...
  • React入门之路

    2018-04-07 20:17:34
    React入门之路 jsx 注释 1、在标签内部的注释需要花括号 2、在标签外的的注释不能使用花括号 ReactDOM.render( /*注释 */ &lt;h1&gt;孙朝阳 {/*注释*/}&lt;/h1&gt;, ...
  • react入门--------第三章react和vue的区别react和vue的区别要从列表渲染、条件渲染、事件绑定、属性绑定 vue 1、列表渲染 v-for 2、条件渲染 v-if 3、事件绑定 v-on 4、属性绑定 v-bind react ...
  • React入门学习

    2017-05-16 18:33:06
    React入门学习
  • 现在最热门的前端框架,毫无疑问是 React 。由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
  • React学习(第一个实例) Vue学的差不多了,谈不上精通,但是单人搭建、开发、组件、路由、vuex什么的都基本没问题了,所以不能闲着,打算边写项目温习Vue,边学习下Reac。 因为是刚开始学习熟悉下写法,所以并...
1 2 3 4 5 ... 20
收藏数 23,386
精华内容 9,354
关键字:

react入门