React 笔记

本文档提供了React框架的基础知识介绍,包括如何搭建开发环境、组件的创建、状态管理和生命周期的理解等内容。
跟我一起学 React ?,只为了缓解大家学习React的痛苦。
懂得也不多,所以有神马我理解错误的地方,请指正。
React 各大BAT都在用的框架,学到就是赚到。

这是我的 Learn 笔记,同样也是一份简明教程。

列一下资料:
React英文版指南

# 先来准备一个基本页面
已经替换为国内的 CDN。
react.js -> React主要核心
react-dom.js -> React DOM 操作
browser.min.js -> 将 babel 转换成浏览器可用的 ES5
<!DOCTYPE html>
<html>
  <head> <meta charset="UTF-8" /> <title>Hello React</title> <script src="http://cdn.bootcss.com/react/0.14.1/react.js"></script> <script src="http://cdn.bootcss.com/react/0.14.1/react-dom.js"></script> <script src="http://cdn.bootcss.com/babel-core/5.8.32/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> // ** Your code goes here! ** </script> </body> </html>
# 写一个简单时间(它看起来想这样)
 props -> properties 属性们
 render -> 渲染
 ReactDom.render(实例化的组件,要渲染到得对象)

 在HelloWorld组件中,传入了一个data属性,对应的是一个Date对象。
 在组件中,通过 this.props.date 拿到Date对象,调用它的toTimeString方法。
 而且本例中我们是用了一个定时器,每500ms我们实例化渲染一次组件,更新时间的值。 <HelloWorld date={new Date()}/> 这是jsx语法,有点类似于HTML5自定义语义标签吧。 可以这么理解,每一个标签就是一个组件,一个对象,因为我们是用的React.createClass方法去创建的,从方法名上就可以看出。
<!DOCTYPE html>
<html>
  <head> <meta charset="UTF-8" /> <title>Hello React</title> <script src="http://cdn.bootcss.com/react/0.14.1/react.js"></script> <script src="http://cdn.bootcss.com/react/0.14.1/react-dom.js"></script> <script src="http://cdn.bootcss.com/babel-core/5.8.32/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> var HelloWorld = React.createClass({ render: function() { return ( <p> 你好, <input type="text" placeholder="输入你的名字"/>! <br/><br/> 现在的时间是:{this.props.date.toTimeString()} </p> ); } }); setInterval(function() { ReactDOM.render( <HelloWorld date={new Date()}/>, document.getElementById('example') ); }, 500); </script> </body> </html>
# 让我们细化知识点吧(JSX语法)
var myDivElement = <div className="foo" />;
// className 就代表 class属性,因为怕属性冲突,所有就另外给了一个名字。
ReactDOM.render(
  myDivElement, 
  document.getElementById('example') );
// 输入:
React.createElement(Profile, null, "click")
// 转义输出为:
<Profile>click</Profile>
var Nav, Profile;
// 输入 (JSX):
var app = <Nav color="blue"><Profile>click</Profile></Nav>; // 转义输出为 (JS): var app = React.createElement( Nav, {color:"blue"}, React.createElement(Profile, null, "click") );
# 组件的命名空间(JSX语法)
// App组件就把这几个组件整合,打包起来了。
var Form = MyFormComponent;
var FormRow = Form.Row; var FormLabel = Form.Label; var FormInput = Form.Input; var App = ( <Form> <FormRow> <FormLabel /> <FormInput /> </FormRow> </Form> ); //用子组件的方式去整合打包 var MyFormComponent = React.createClass({ ... }); MyFormComponent.Row = React.createClass({ ... }); MyFormComponent.Label = React.createClass({ ... }); MyFormComponent.Input = React.createClass({ ... }); //使用 React.createElement 的第三个参数 var App = ( React.createElement(Form, null, React.createElement(Form.Row, null, React.createElement(Form.Label, null), React.createElement(Form.Input, null) ) ) );
# 布尔属性、表达式与注释(JSX语法)
// 禁用样式的按钮
<input type="button" disabled />;
<input type="button" disabled={true} />; // 正常使用的按钮 <input type="button" />; <input type="button" disabled={false} />; // 输入 (JSX): var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>; // 三元运算符,window.isLoggedIn 存在输出<Nav />组件,否则输出<Login/>组件 // 输出 (JS): var content = React.createElement( Container, null, window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login) ); var content = ( <Nav> {/* 子组件注释,加上 {} 花括号 */} <Person /* 组件 属性 注释 */ name={window.isLoggedIn ? window.name : ''} // end of line comment /> </Nav> );
# 属性传入组件的多种方式(JSX语法)
//变量放在{}中
var component = <Component foo={x} bar={y} />;


var component = <Component />;
component.props.foo = x; // 不推荐,最丑的做法
component.props.bar = y; // 不推荐,颜值低得人可以这么干 //传入对象的方式传入属性 var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />; //注意,后面会覆盖前面的 var props = { foo: 'default' }; var component = <Component {...props} foo={'override'} />; console.log(component.props.foo); // 输出为'override'
# JSX 陷阱(JSX做了一些处理防止XSS攻击)
// 会显示 “First · Second” 
<div>{'First · Second'}</div>

// 它会显示 "First · Second" <div>First · Second</div> // 正确做法,帅的人都这么干 <div>{'First \u00b7 Second'}</div> <div>{'First ' + String.fromCharCode(183) + ' Second'}</div> // 同时你还可以这样玩,加上[],以数组的形式。 <div>{['First ', <span>·</span>, ' Second']}</div> //但是有的适合,我的项目中就需要这样干,就要原来的。 //给dangerouslySetInnerHTML传入一个对象,其中有一个__html属性,其中写了你的文本。 <div dangerouslySetInnerHTML={{__html: 'First · Second'}} /> //假如你想加上自定义属性,必须加上data-前缀 //以aria-开头的属性页可以被渲染出来 <div data-custom-attribute="foo" /> <div aria-hidden={true} />
# 组件生命周期(别纠结这是干什么,纠结你就输了,先看一看文字,不用去弄懂他们,跳过都行,细节后面在讲解)
初始化阶段
getDefaultPropos:只调用一次,实力之间共享引用
getInitialState:初始化每个实例特有的状态
componentWillMount:render之前最后一次修改状态的机会
render:只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和DOM输出
componentDidMount:成功render并渲染完成真实DOM后触发,可以修改DOM
运行中阶段
componentWillReceiveProps:父组件修改属性触发,可以修改新属性,修改状态
shouldComponentUpdate:返回false会阻止render调用
componentWillUpeate:不能修改属性和状态
render:只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和DOM输出 componentDidUpdate:可以修改DOM
销毁阶段:
componentWillUnMount:在删除组件之前进行清理操作,比如计时器和事件监听器。

附上一些我当初的截图笔记,可以看出他们运行顺序(当初用的是JSX转换库):

初始化阶段

<script type="text/jsx"> $(function(){ var count = 0; var style={ color:"red", border:"1px #000 solid" }; var HelloWorld = React.createClass({ getDefaultProps:function(){ console.log(1); return {name:"Yugo"}; }, getInitialState:function(){ console.log(2); return { myCount: count = count+1 , ready: "false" }; }, componentWillMount:function(){ console.log(3); // 修改状态 this.setState({ready:"true"}); }, render:function(){ console.log(4); return <p ref="childp">Hello,{this.props.name?this.props.name:"World"}<br/> {this.state.ready} {this.state.myCount}</p>; }, componentDidMount:function(){ console.log(5); //改变DOM $(React.findDOMNode(this)).append("666666"); }, }) React.render(<div style={style}><HelloWorld></HelloWorld></div>,document.body) }); </script>

初始化阶段事件顺序

运行中阶段

     var style={
        color:"red",
        border:"1px #000 solid" }; var HelloWorld = React.createClass({ componentWillReceiveProps:function(){console.log(1);}, shouldComponentUpdate:function(){console.log(2);return true;}, componentWillUpdate:function(){console.log(3);}, render:function(){ console.log(4); return <p>Hello,{this.props.name?this.props.name:"World"}</p>; }, componentDidUpdate:function(){console.log(5);}, }); var HelloUniverse = React.createClass({ getInitialState:function(){ return {name:''}; }, handleChange:function(event){ this.setState({name: event.target.value}) }, render:function(){ return <div> <HelloWorld name={this.state.name}></HelloWorld> <br/> <input type="text" onChange={this.handleChange} /> </div> }, }); React.render(<div style={style}><HelloUniverse></HelloUniverse></div>,document.body)

运行中阶段事件顺序

销毁阶段

 var style={
        color:"red",
        border:"1px #000 solid" }; var HelloWorld = React.createClass({ render:function(){ console.log(4); return <p>Hello,{this.props.name?this.props.name:"World"}</p>; }, componentWillUnmount:function(){ console.log("Delete`````````!"); }, }); var HelloUniverse = React.createClass({ getInitialState:function(){ return {name:''}; }, handleChange:function(event){ if(event.target.value == 123){ React.unmountComponentAtNode(document.body); return; } this.setState({name: event.target.value}) }, render:function(){ return <div> <HelloWorld name={this.state.name}></HelloWorld> <br/> <input type="text" onChange={this.handleChange} /> </div> }, }); React.render(<div style={style}><HelloUniverse></HelloUniverse></div>,document.body)

销毁阶段
# 来一个简单小栗子(根据状态去做不同的行为)
state -> 状态
React.createClass方法,我们是传入的一个对象。
而这个对象的生命周期分为三个,初始化、运行中、销毁阶段。
再介个栗子中,getInitialState是属于初始化阶段的。
他返回了一个对象,这个对象中包含组件的状态。
我们可以通过this.state去获得这个对象。
通过setState(data, callback)方法去设置状态,同样是传入对象。
onClick就是鼠标单击事件喽,鼠标单击执行自定义函数handleClick。
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') );
什么时候使用状态(百度翻译了一下原文)?
你的大部分组件应该只需从props中取一些数据并渲染它。然而,
有时你需要对用户输入、服务器请求或时间的推移作出反应。为此您使用state状态。
尽可能保持尽可能多的组件成为可能的state状态。
通过这样做,您将分离到它最合乎逻辑的地方,并尽量减少冗余。
一个常见的模式是创建多个无状态的组件,只是提供props数据,
并有一个有state状态的组件上面,通过其state状态通过子组件的层次。
有状态组件封装了所有的交互逻辑,而无状态的组件专注呈现数据。
建设一个有状态的组件时,考虑其状态的最小可能性,
this.state应该只包含需要代表你的UI状态的最小数据量,不要包含计算数据、反应元件(基于基本的道具和状态建立他们)

用我自己的话说吧(2个小栗子):
我能吐槽这个最小可能性,和最小数据量吗?

当需要改变组件的行为的时候,我们可能要去判断状态。
?一:有病状态就该吃药,没病也别没事瞎嗑药,容易出事,但是有病的还是少数人。

?二:师傅有五个徒弟,分为大师兄徒弟(武力值最高),和其他徒弟俩类。
师傅出去云游,估计某处青楼里创作惊世神功,大师兄通常是代理师傅。根据门派的状态去给其他师弟师妹派任务。
大师兄:二师弟,厨房木有米了,你负责下山去买米。
       只见大师兄拿出笔和纸,写了一大页满的。考虑到师傅10年后回来的概率(20%),与各位师兄弟的饭量,刚刚好200万。
       买200万斤吧!,多一斤也不要,我就要这个最小数据量,不包含其他算法处理,不要因为价格,带的钱不够,就买少了,就要实实在在的这么多,带上神兽麒麟,驼回来,考虑到200年之后没米吃,对,就这么干。 还有你不要有反应元件,我知道你比较冲动,不能用为老板给的价格不合理,你就砍了他,咱门派的人不乱杀人,摊上事了,别冲动,好好解决。跟他谈个好几年的价格也是可以的。 二师弟:( ⊙ o ⊙ )啊!!!,师兄高瞻远就,我这就去办。 (尼玛,考虑最小可能性也没必要这么干吧,200年啊!!!,还最小数据量,尼玛怎么算得啊!拉格朗日一下就出来了?) 大师兄:三师妹,你就负责服侍大师兄我吧!来,先捶捶腿。 三师妹:~~~~(>_<)~~~~ 大师兄:四师弟,马桶堵了,你去掏马桶。 四师弟:哦!(逼了狗了~,还不如买米去。) 大师兄:五师弟,念你年纪小,上山去砍柴,多锻炼才能长得结实。 五师弟:.....(默默背上柴刀走了) 故事就是这样,这个故事告诉我们,要么做大师兄,要么回家种田。 (管事的,管状态的越少越好,一个最好,这样才不会乱。)
# 看看大师兄和师弟们是如何协作的。

介个是一个评论中的头像组件

// Avatar组件包含2个子组件 ProfilePic、ProfileLink。
// ProfilePic:个人头像
// ProfileLink:个人主页链接
// Avatar组件传入了username属性props
// 通过 this.props.username 再传递给子组件 var Avatar = React.createClass({ render: function() { return ( <div> <ProfilePic username={this.props.username} /> <ProfileLink username={this.props.username} /> </div> ); } }); var ProfilePic = React.createClass({ render: function() { return ( <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} /> ); } }); var ProfileLink = React.createClass({ render: function() { return ( <a href={'https://www.facebook.com/' + this.props.username}> {this.props.username} </a> ); } }); ReactDOM.render( <Avatar username="pwh" />, document.getElementById('example') );
就如同大师兄知道没米,叫二师弟去买米。
师傅留下麒麟,没带走,然后又交给二师弟去驮米一样。
(不知道师傅回来会不会一巴掌打屎他)
# 关于子组件
<Parent><Child /></Parent>
//通过 this.props.children 可以操作子组件

// 第一次输出 <Card> <p>Paragraph 1</p> <p>Paragraph 2</p> </Card> // 第二次更新输出 <Card> <p>Paragraph 2</p> </Card> //Paragraph 1 将会被移除掉
今天是第二天,时间是1点半。
惆怅,今天11点钟起来,帮管朋友的Server2003服务器(老的不像样)挂掉了。
最近逃课也经常被点到,我也是醉了。
言归正传,继续学习。
# 动态组件
array.map(value)函数遍历一个数组。
result.id 是起了标识作用
render: function() {
    var results = this.props.results; return ( <ol> {results.map(function(result) { return <li key={result.id}>{result.text}</li>; })} </ol> ); }
标识id应该在组件上,
// 错误!丑的人都这样干,反正我是不这样干。
var ListItemWrapper = React.createClass({
  render: function() { return <li key={this.props.data.id}>{this.props.data.text}</li>; } }); var MyComponent = React.createClass({ render: function() { return ( <ul> {this.props.results.map(function(result) { return <ListItemWrapper data={result}/>; })} </ul> ); } }); // 正确 :) var ListItemWrapper = React.createClass({ render: function() { return <li>{this.props.data.text}</li>; } }); var MyComponent = React.createClass({ render: function() { return ( <ul> {this.props.results.map(function(result) { return <ListItemWrapper key={result.id} data={result}/>; })} </ul> ); } });
# PropTypes,类型约束
为了性能考虑,只在开发环境验证 propTypes
对于我这种没有队友的人来说,感觉鸡肋,多此一举,大家不喜欢就跳过吧~我也跳了。
React.createClass({
  propTypes: {
    // 可以声明 prop 为指定的 JS 基本类型。默认
    // 情况下,这些 prop 都是可传可不传的。
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool, optionalFunc: React.PropTypes.func, optionalNumber: React.PropTypes.number, optionalObject: React.PropTypes.object, optionalString: React.PropTypes.string, // 所有可以被渲染的对象:数字, // 字符串,DOM 元素或包含这些类型的数组。 optionalNode: React.PropTypes.node, // React 元素 optionalElement: React.PropTypes.element, // 用 JS 的 instanceof 操作符声明 prop 为类的实例。 optionalMessage: React.PropTypes.instanceOf(Message), // 用 enum 来限制 prop 只接受指定的值。 optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), // 指定的多个对象类型中的一个 optionalUnion: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, React.PropTypes.instanceOf(Message) ]), // 指定类型组成的数组 optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), // 指定类型的属性构成的对象 optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), // 特定形状参数的对象 optionalObjectWithShape: React.PropTypes.shape({ color: React.PropTypes.string, fontSize: React.PropTypes.number }), // 以后任意类型加上 `isRequired` 来使 prop 不可空。 requiredFunc: React.PropTypes.func.isRequired, // 不可空的任意类型 requiredAny: React.PropTypes.any.isRequired, // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接 // 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。 customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error('Validation failed!'); } } }, });
# 把自身所有属性,传给子组件
var CheckLink = React.createClass({
  render: function() { // 这样会把 CheckList 所有的 props 复制到 <a> return <a {...this.props}>{'√ '}{this.props.children}</a>; } }); ReactDOM.render( <CheckLink href="/checked.html"> Click here! </CheckLink>, document.getElementById('example')
# Mixins(学过less、sass可能对这个比较熟悉)
说白了这货就是一个代码块,在哪用,就原封不动复制到哪。
不过要放在这个 mixins 对应的数组里面。
假如传入的多个mixins里面包含多个生命周期函数。
保证都会执行到得,首先按 mixin 引入顺序执行 mixin 里方法,
最后执行组件内定义的方法。
第一步,从getInitialState 得到初始化 seconds = 0
第二步,componentWillMount 中给当前对象挂了一个intervals数组。
第三步,render渲染模板到页面
第四步,componentDidMount,DOM渲染完毕后。
       调用 this.setInterval(this.tick, 1000)。
第五步,this.intervals.push(setInterval.apply(null, arguments)); 给intervals数组推入一个函数。里面一直就只有一个元素。 至于为什么推入数组中,是为了闭包,更好的销毁。 这个函数是系统的setInterval定时器函数。 用apply触发,第一个参数是this代表的值,第二个是参数。 setInterval是在全局window对象下面的。 而当前环境的this,是 React 组件对象,所以才用apply方法。 每一秒调用一次 this.tick,更新 seconds的状态值。 第六步,更新状态重新渲染。 第七步,1秒后继续更新状态再渲染。 在控制台中的输出顺序是: 1234563636363....
var SetIntervalMixin = {
  componentWillMount: function() { console.log(2); this.intervals = []; }, setInterval: function() { console.log(5); this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { console.log(7) this.intervals.map(clearInterval); } }; var TickTock = React.createClass({ mixins: [SetIntervalMixin], // 引用 mixin getInitialState: function() { console.log(1); return {seconds: 0}; }, componentDidMount: function() { console.log(4); this.setInterval(this.tick, 1000); // 调用 mixin 的方法 }, tick: function() { console.log(6); this.setState({seconds: this.state.seconds + 1}); }, render: function() { console.log(3); // console.log(this.intervals); return ( <p> React has been running for {this.state.seconds} seconds. </p> ); } }); ReactDOM.render( <TickTock />, document.getElementById('example') );
# 把自身部分传给子组件
利用了ES6的析构特性
var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x; // 1 y; // 2 z; // { a: 3, b: 4 } 关于bind方法 this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var getX = module.getX; getX(); // 9, 因为在这个例子中,"this"指向全局对象 // 创建一个'this'绑定到module的函数 var boundGetX = getX.bind(module); boundGetX(); // 81
var FancyCheckbox = React.createClass({
  render: function() { var { checked, ...other } = this.props; var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked'; // `other` 包含 { onClick: console.log } 但 checked 属性除外 return ( <div {...other} className={fancyClass} /> ); } }); ReactDOM.render( <FancyCheckbox checked={true} onClick={console.log.bind(console)}> Hello world! </FancyCheckbox>, document.getElementById('example') );
# 事件与表单组件
event.target -> 代表事件产生的对象(事件目标)
event.target.value -> 事件目标的value属性值
//受限组件,你要是把值直接写成Value属性。
//那你就什么都输入不了。
var FancyCheckbox = React.createClass({
  render: function() { return <input type="text" value="Hello!" />; } }); ReactDOM.render( <FancyCheckbox checked={true} onClick={console.log.bind(console)}> Hello world! </FancyCheckbox>, document.getElementById('example') ); //设置初始值用 defaultValue render: function() { return <input type="text" defaultValue="Hello!" />; } // 多选 <select multiple={true} value={['B', 'C']}> // 这样使用更为优雅,这是一个受限组件 <textarea name="description" value="This is a description." /> //正确的做吧是把它定义为状态,当值改变触发更新 getInitialState: function() { return {value: 'Hello!'}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function() { var value = this.state.value; return <input type="text" value={value} onChange={this.handleChange} />; }
# React的虚拟DOM
我们可以知道React显示出来是在render渲染到页面之后。
而在之前的DOM标签全是虚拟的,所以才能让运行速度非常的快。
但是我们也可以照样操作DOM,不过要等真实DOM渲染之后。
# ref 属性
<input ref="myInput" />
var input = this.refs.myInput; // 得到实例 // this.refs['myInput'] 也可以 var inputValue = input.value; // 得到value属性值 var inputRect = input.getBoundingClientRect(); //得到React实例
ES6新特性
(ref) => this.myTextInput = ref

等于

function(ref){ return this.myTextInput = ref }
var MyComponent = React.createClass({
  handleClick: function() {
    //使得实例获得焦点
    this.myTextInput.focus(); }, render: function() { // 假如ref是一个函数,那么会传一个this对象到为参数传进去 //(好像这样才解释的通) return ( <div> <input type="text" ref={(ref) => this.myTextInput = ref} /> <input type="button" value="Focus the text input" onClick={this.handleClick} /> </div> ); } }); ReactDOM.render( <MyComponent />, document.getElementById('example') );
这几天,有点忙,老是被朋友叫去帮他们调试JSP,一调一晚上。
对此事,我只想说一句,我在北方的寒夜里,玩着灵车漂移。
突然想多看看视频,自己了解深刻一点在写。
So Sorry!朋友们
接下来会有React事件,Mixin深入(源码阅读,双向绑定),动画,尽请期待。

React Router 体验

 

渲染 Route

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

render((
    <Router history={hashHistory}> <Route path"/" compnent={App}/> </Router> ), document.getElementById('app'))

增加页面

modules/Boys.js

import React from 'react'
export default React.createClass({ render(){ return <div>我是男神!</div> } })

modules/Girls.js

import React from 'react'

export default React.createClass({ render(){ return <div>我是女神!</div> } })

使用 Route 组件导航

import React from 'react'
import {render} from 'react-dom' import {Router,Route,hashHistory} from 'react-router' import App from './modules/App' import Boys from './modules/Boys' import Girls from './modules/Girls' render({ <Router history={hashHistory}> <Route path='/' component={App} /> <Route path='/boys' component={Boys} /> <Route path='/girls' component={Girls} /> </Router> }, document.getElementById('app'))

使用 Link 进行跳转组件

modules/App.js

import React from 'react'
import { Link } from 'react-router' export default React.createClass({ render(){ return { <div> <h1>明星特区</h1> <ul role='nav'> <li><Link to='boys' activeStyle={{ color: 'red'}}>男神</Link></li> <li><Link to='girls' activeClassName='active'>女神</Link></li> </ul> {this.props.children} </div> } } })

从 Link 到 NavLink

modules/NavLink.js

import React from 'react'
import { Link } from 'react-router' export default React.createClass({ render(){ return <Link {...this.props} activeClassName='active'/> } })

App.js

import NavLink from './NavLink'

<li><NavLink to='/boys'>男神</NavLink></li> <li><NavLink to='/girls'>女神</NavLink></li>

URL 参数的传递

module/Boys.js

import React from 'react'
export default React.createClass({ render() { return ( <div> <h2>大家好,我是{this.props.params.boyName}!</h2> </div> ) } })

index.js

<Route path="/boys/:boyName" component={Boys}/>

修改 Link

<li><Link to="/boys/宋仲基">宋仲基</Link></li>

嵌套 Route

index.js

<Route path="/boys" component={Boys}>
  <Route path="/boys/:boyName" component={Boy}/> </Route>

Boys.js

<div>
  <h2>我的男神们:</h2> <ul> <li><Link to="/boys/宋仲基">宋仲基</Link></li> <li><Link to="/boys/吴亦凡">吴亦凡</Link></li> </ul> {this.props.children} </div>

App.js

import NavLink from './NavLink'
// ...
<li><NavLink to="/boys/宋仲基">宋仲基</NavLink></li> <li><NavLink to="/boys/吴亦凡">吴亦凡</NavLink></li> // ...

IndexRoute 首页默认路由

modules/Home.js

import React from 'react'
export default React.createClass({ render(){ return <div> 男生与女生 </div> } })

App.js

import Home from './Home'
// ......
<div>
    {this.props.children|| <Home/>} </div>

index.js

// ...
import { Router, Route, hashHistory, IndexRoute } from 'react-router'
import Home from './modules/Home' // ... render(( <Router history={hashHistory}> <Route path="/" component={App}> <IndexRoute component={Home}/> <Route path="/boys" component={Boys}> <Route path="/boys/:boyName" component={Boy}/> </Route> <Route path="/girls" component={Girls}/> </Route> </Router> ), document.getElementById('app'))

IndexLink

import { IndexLink, Link } from 'react-router'
// ...
<li>
<IndexLink to='/' activeClassName='active'>Home</IndexLink> </li> // ...

不是当前组件子路由被激活,该路由才会显示

<li><Link to="/" activeClassName="active" onlyActiveOnIndex={true}>Home</Link></li>

使用 browserHistory

现代浏览器运行 JS 操作 URL 而不产生 HTTP 请求

// ...
import { Router, Route, browserHistory, IndexRoute } from 'react-router'

render((
  <Router history={browserHistory}> //... </Router> ), document.getElementById('app'))

使用程序控制导航

import React from 'react'
import NavLink from './NavLink' export default React.createClass({ contextTypes: { router: React.PropTypes.object }, // add this method handleSubmit(event) { event.preventDefault() const boyName = event.target.elements[0].value const path = `/repos/${boyName}` this.context.router.push(path) console.log(path) }, render() { return ( <div> <h2>我的男神们:</h2> <ul> <li><NavLink to="/boys/宋仲基">宋仲基</Link></li> <li><NavLink to="/boys/吴亦凡">吴亦凡</Link></li> <li> <form onSubmit={this.handleSubmit}> <input type="text" placeholder="boyName"/> / {' '} <button type="submit">Go</button> </form> </li> </ul> {this.props.children} </div> ) } })
 前端

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值