http://www.ruanyifeng.com/blog/2015/03/react.html
阮一峰的网络日志 » 首页 » 档案分类:
React 入门实例教程
现在最热门的前端框架,毫无疑问是 React 。
上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。
由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。
既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 React 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 React 本身还在不断变动,API 一直在调整,至今没发布1.0版。
我学习 React 时,就很苦恼。有的教程讨论一些细节问题,对入门没帮助;有的教程写得不错,但比较短,无助于看清全貌。我断断续续学了几个月,看过二十几篇教程,在这个过程中,将对自己有帮助的 Demo 都收集下来,做成了一个库 React Demos 。
下面,我就根据这个库,写一篇全面又易懂的 React 入门教程。你只需要跟着每一个 Demo 做一遍,就能初步掌握 React 。当然,前提是你必须拥有基本 JavaScript 和 DOM 知识,但是你读完就会发现,React 所要求的预备知识真的很少。
零、安装
React 的安装包,可以到官网下载。不过,React
已经自带 React 源码,不用另外安装,只需把这个库拷贝到你的硬盘就行了。
Demos
$ git clone git@github.com:ruanyf/react-demos.git
如果你没安装 git, 那就直接下载 zip 压缩包。
下面要讲解的12个例子在各个 Demo
子目录,每个目录都有一个 index.html
文件,在浏览器打开这个文件(大多数情况下双击即可),就能立刻看到效果。
需要说明的是,React 可以在浏览器运行,也可以在服务器运行,但是本教程只涉及浏览器。一方面是为了尽量保持简单,另一方面 React 的语法是一致的,服务器的用法与浏览器差别不大。Demo13
是服务器首屏渲染的例子,有兴趣的朋友可以自己去看源码。
一、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
节点(查看 demo01
),运行结果如下。
三、JSX 语法
上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写(查看 Demo02
)。
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 变量。如果这个变量是一个数组,则会展开这个数组的所有成员(查看 demo03
)。
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 方法就用于生成一个组件类(查看 demo04
)。
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
组件包含了两个顶层标签:h1
和p
。
组件的用法与原生的 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
属性。它表示组件的所有子节点(查看 demo05
)。
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
。更多的 React.Children
的方法,请参考官方文档。
六、PropTypes
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes
属性,就是用来验证组件实例的属性是否符合要求(查看 demo06
)。
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`.
更多的PropTypes
设置,可以查看官方文档。
此外,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
属性(查看 demo07 )。
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
、Copy
、Scroll
等,完整的事件清单请查看官方文档。
八、this.state
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08
)。
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
读取(查看 demo9
)。
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):组件判断是否重新渲染时调用
这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10
)。
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 (查看 demo11
)。
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's official site
- React's official examples
- React (Virtual) DOM Terminology, by Sebastian Markbåge
- The React Quick Start Guide, by Jack Callister
- Learning React.js: Getting Started and Concepts, by Ken Wheeler
- Getting started with React, by Ryan Clark
- React JS Tutorial and Guide to the Gotchas, by Justin Deal
- React Primer, by Binary Muse
- jQuery versus React.js thinking, by zigomir
(完)
广告(购买广告位)
留言(250条)
实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。
相信阮一峰老师~ 先留言后看w 前端新人一只 来这学了很多东西
React自己也折腾了好几个月~ 挺好玩~
thx~
前排支持, 希望能看到你更多的文章.
阮老师的最近的每篇文章,内容都是当下最热门的话题,并且适合初学者阅读。 好厉害!
之前从未接触过React,看了这篇博文之后就有了大概的印象了,提供的示例通俗易懂,非常感谢!
学习了!!!
留个链接, 我是 React 中文社区维护者之一(跟 Facebook 无关..).
社区交流的渠道可以在 http://nav.react-china.org/ 查看.
如果大家有兴趣追最新的消息, 交流跟分享 React, 可以细看一下.
Unmounting:已移出真实 DOM, 是移除吧, 吹毛求疵一下...
真是一篇很好的入门教程!
最近正用React写项目,老阮关于“状态机”的论述也很有帮助
謝謝好文,但是我想指出你文中說 React Native 想要「同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机」是不正確的。
歷史上所有標榜 "Write once, run everywhere" 的項目都失敗了。 React Native 在發表時,說的是 "Learn once, write everywhere"。瀏覽器、 iOS 及 Android 的後端 js 邏輯可以共用,UI 還是得寫三次,但架構版型的思考模式會一樣 (都用 CSS flexbox),畫面元件還是得從 換成 。
一峰大师 的文章果然赞!!!react入门必读文章哈!
引用曲双如的发言:实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。
他在支付宝
不能更赞啊,谢谢阮老师
老师的文章总是那么深入浅出而又博大精深。daomubiji.org
加油~
基于React的Reagent很赞。
凡是使用 JSX 的地方,都要加上 type="text/jsx" 现在的 react 版本不需要了
Donate 没了?
引用busyStone的发言:凡是使用 JSX 的地方,都要加上 type="text/jsx"现在的 react 版本不需要了
那是转换成 原生 js 后, 才不用添加的吧.
有些文章不能看了,比如
http://www.ruanyifeng.com/blog/2008/03/imdb_database_structure.html
相信看了您的文章,就很容易入门了吧.果断买本《如何变得有思想》支持一下.
哈哈,一峰老师名气可真大啊。。
一峰老师超赞,布道大师
阮兄能否在结合flux一起讲一下react。
React 可能是个很 NB 的东西,可是看起来很复杂,我没有什么好感。当然,我对它没有好感并不影响它是个 NB、伟大的东西。
看了二十几篇教程就写出个这。。?
阮兄,
请问 React 适合开发什么类型的项目?
如果我的项目围绕在电子商务,酒店订购,餐厅(包括开发管理界面),
React 和 nagularjs 哪一个更适合我呢?
思想差异,优缺点能否说一说 ?
由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。
props,在这里很常见的用法是传参,显然形参你改了也灭用
而state这个属性就要好好把玩了,也说了,交互中很常见的状态
新技术介绍,不错。
学习了,感觉特别棒。
真的很不错,希望阮大侠继续React在中国的布道。
能否解释下 第十个Demo中的isMounted方法的作用和意义?谢谢。
期待阮老师在出一个Reflux的教程
阮老师的博客内容总是这么棒~~
试了一下,四组件类的名称必须是大写字母开头!!!
写的真好,已经入门
React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。引用luobotang的发言:React 可能是个很 NB 的东西,可是看起来很复杂,我没有什么好感。当然,我对它没有好感并不影响它是个 NB、伟大的东西。
引用Mrluobo的发言:能否解释下 第十个Demo中的isMounted方法的作用和意义?谢谢。
只有组件还处于挂载状态下,才有setState从而更新视图的意义。
就是 class 属性需要写成 className
新版的不需要了 直接写成class 就可以了
写的真好。
这React看起来不是那么简单,语法都搞不清了。改变好大。另外,这东西能debug吗?
写的很通俗易懂
通俗易懂,大赞
Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用。
下面是对 React Native 官方文档的完整中文翻译教程:http://wiki.jikexueyuan.com/project/react-native/
引用haohao的发言:试了一下,四组件类的名称必须是大写字母开头!!!
我也发现了
看起来怎么又把模板揉进JS里了?
我有点儿贪心了:React能否开发游戏/移动端游戏?
React.findDOMNode 这个调用报错:React is undefined. 这是怎么回事啊?大神
勘误:
只有当子节点多余1个时
多于
一个错别字:
只有当子节点多余1个时
多于
打算先把这些demo过一遍
非常感谢您分享这篇文章,由衷地感谢!
现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
引用刘大的发言:看了二十几篇教程就写出个这。。?
那你还想咋地?
请问两个独立组件之间有什么好的交互方式
感谢博主!现学现用,很有参考价值
第九个例子最好clearInterval一下
引用初学者的发言:现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
那你最好去当个教师。不要做前端了
貌似this可以随便用都无视函数作用域?
不错,简单易懂
写的很好,读的很有收获
$ git clone git@github.com:ruanyf/react-demos.git
应该是:
https://github.com/ruanyf/react-demos.git
这样不需要SSH的也可以直接clone
学习了!希望出现flux、reflux、redux教程!
文章开头讲到参见《也许,DOM 不是答案》,和React没太大关系。《也许,DOM 不是答案》是篇值得深思的文章,那篇文章给出的答案是新的页面渲染方式,倾向仍然是web端。
而React只是稍微新一点的编写方式。Native解决的是减少工作量,统一的代码,性能能好吗?已经有太多项目做过这样的尝试了,还说什么“如果能够实现,整个互联网行业都会被颠覆”,别逗了。
React不会解决那篇文章说的问题,也挨不上关系。
您好:我想问您这个框架可以开发网页版组态软件么?可以和requriejs配合么?
Pretty cool!
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
React.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
阮老师,为什么插入之后的html结构,会分别有两个span标签包裹着Hello和{this.props.name}呢?
这段代码是demo4里面的
赞!条理清晰,比较全面而简单,谢谢阮老师!
虽然跟着demo都敲了一下,但是发现自己什么都没有学会,render是干嘛的不知道,还有就是除了这些方法还有哪些方法,也不清楚,是不是我学的太浅了?
老师,能否写个flux入门?
我想知道如何外部引入jsx
申明了type="text/jsx" 引入就会失败
不申明就会有语法错误!
引用初学者的发言:现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
所以充其量你永远只是一个小码农。不愿接受新事物,墨守陈规。
看過一些資料, 感覺一直模模糊糊,
看了一下您的教學, 馬上釐清觀念! 感謝老師
写得太好了,太好了
阮老师 好像是在淘宝 少年加油吧引用曲双如的发言:实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。
文中说只要调用 setState 方法,就会自己调用 render 方法,重新渲染组件,
八、表单 这节中,我看到 p 标签中使用 {value},input 标签中也是使用value={value},
但是改变 input 中内容,只有 p 中内容跟着改变了,input 的 value 属性值没有跟着改变,
那 render 方法到底是怎么执行的呢?没有重新渲染 input 吗?
您好,我安装了git,用webstorm去push你的代码,总是失败
阮老师自学能力太强了
引用rolin的发言:貌似this可以随便用都无视函数作用域?
注意看代码下面的bind(this),这是通过function的bind方法指定了作用域,相关链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
写得真好,学习中
创建组件的变量 首字母要用大写才有用 不知道大家是不是这样
写的很好,有的看官方没看懂,看你的整明白了,支持一下
引用whws的发言:文中说只要调用 setState 方法,就会自己调用 render 方法,重新渲染组件,
八、表单 这节中,我看到 p 标签中使用 {value},input 标签中也是使用value={value},
但是改变 input 中内容,只有 p 中内容跟着改变了,input 的 value 属性值没有跟着改变,
那 render 方法到底是怎么执行的呢?没有重新渲染 input 吗?
render 的时候重新生成了 Virtual DOM,但重新渲染UI时,React 只会对 Virtual DOM 中发生改变了的部分进行重新渲染。render 后 Virtual DOM 中 input 的 value 属性值其实发生了变化,但和真实 DOM 中 input 的 .value 想用,故没有渲染到UI中。
PS. 你可以通过在 input 上加上 ref="myTextInput",并在 handleChange 里加入 console.log(this.refs["myTextInput"].props); 来打印 Virtual DOM 的属性值来发现其中奥妙。
引用前端菜鸟的发言:虽然跟着demo都敲了一下,但是发现自己什么都没有学会,render是干嘛的不知道,还有就是除了这些方法还有哪些方法,也不清楚,是不是我学的太浅了?
我建议把每一个3分钟就能看完的例子,用30分钟进行各种改写试验,就能够深入一些。
引用Zoe的发言:阮老师,为什么插入之后的html结构,会分别有两个span标签包裹着Hello和{this.props.name}呢?
你应该也发现了,他们都有各自的 reactid,是React为了实现以后的查找元素和局部重新渲染。
第八个例子中你可以发现这个事实,选中前面的You或后面Click to toggle中某些字母,此时触发点击事件造成 like 部分的改变,没有使你选中区域的背景和焦点丢失,就是只重绘了中间的那个 span。
引用busyStone的发言:凡是使用 JSX 的地方,都要加上 type="text/jsx"现在的 react 版本不需要了
目前0.13 版本还是要加的JSXTransformer.js 的,除非转化为原生js
想要看视频教程的同学可以到这里看
http://piliyu.com
如果我想在react组件里嵌入一个jquery的datepicker组件应该怎么来做?
感谢老师的分享
browser.min.js 是用来干嘛的 我看到有的教程里面用的是 JSXTransformer.js 这两者有什么区别吗?
引用兴杰的发言:阮兄,
请问 React 适合开发什么类型的项目?
如果我的项目围绕在电子商务,酒店订购,餐厅(包括开发管理界面),
React 和 nagularjs 哪一个更适合我呢?
思想差异,优缺点能否说一说 ?
angular适合快速搭建应用,组建比较全,依赖入驻思想,经常写java服务的同学可能很试用,但其根本没有脱离dom结构,是渲染dom结构展现,尤其双向数据绑定在复杂数据交互时候,性能不高;react比较轻,自己重写的虚拟dom渲染比较独特,但组件不全,很多需要自己扩展,写核心的应用或者酷炫效果应该不错,具体看你实际应用吧
你好,我最近在学习react的时候 ,看的是facebook.github.io/react/docs/tutorial.html 的例子,发现怎么好像提交数据时候的url 和 请求数据的url 一样的,这个是怎么回事,似乎和我们常见web 有点不太一样,还望指导一下,谢谢
"Demo11 是服务器首屏渲染的例子"这里说的应该是Demo12吧!
看你Demo11中说ajax请求的数据要通过setState来触发渲染,事实上ajax请求之前就会调用初始的state默认渲染一次,例子中初始state比较简单:
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
}
那问题是我请求的数据结构很复杂,那初始state必须得完全照搬复杂的数据结构?要不然第一次渲染时就会报错!
引用初学者的发言:现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
你说的这段话很符合你的用户名
阮老师,JSX能在浏览器控制台断点吗?我试了好像不行?是我方法错了吗?
又重新看了一遍,主要是最近react-native推出了android的版本;所以react很值得深入学习理解;最终的方向还是在react-native方向;我看最近很多比如www.reactjs.cn,http://www.webdoes.com/blog/archives/725,都专门讲解了react-native,也很不错,值得学习一下;感谢阮老师。
10分钟入门React系列
一个是get请求,一个是post请求
引用funye的发言:
你好,我最近在学习react的时候 ,看的是facebook.github.io/react/docs/tutorial.html 的例子,发现怎么好像提交数据时候的url 和 请求数据的url 一样的,这个是怎么回事,似乎和我们常见web 有点不太一样,还望指导一下,谢谢
牛逼,这demo都有2000+的star了
大神,git不了啊,老说没权限。。。
引用和风的发言:大神,git不了啊,老说没权限。。。
直接用浏览器访问这个页面,然后Download ZIP
https://github.com/ruanyf/react-demos
阮老师第一个例程里面的<script type="text/babel"> 貌似写错了
<script type="text/jsx">
// ** Our code goes here! **
</script>
script type="text/babel" 写成了 script type="text/jsx"
@星光:
谢谢指出,已经更正了。
引用haohao的发言:试了一下,四组件类的名称必须是大写字母开头!!!
啊,多谢,我就在这地方遇到坑了。阮老师可以考虑补充进去哈:)
我个人的感觉,JSX是需要React解析的,这种语法糖也会改变开发JavaScript的开发方式,时间久了会导致原生JavaScript不熟了,因为好多问题你要前端非常熟悉JavaScript,否则就导致漫天大海的在网上找解决方案。
我个人觉得,类似React的这种东东不要改变JavaScript写代码方式,可以在用JavaScript编写面向对象的组件上解决组件开发中单点的处理,而不是弄一套体系改变前端开发人员的开发方式。
ruanyifeng大大,
PropTypes 熟悉这一部分是不是有问题哈 .
可以拿最新的 0.14.0 测试一下哦 .
引用初学者的发言:现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
- - 那 Facebook 为啥要用 , 不是你想的那样的 .
没有 MVC 框架 , 你写 bootstrap semantic UI 试试
引用rolin的发言:貌似this可以随便用都无视函数作用域?
函数结尾有个.bind(this),这个this就是传入当前作用域。
还不支持windows 555555555
能有比较完善的demo吗?
有没有什么优秀的开发工具来支持react?
引用星光的发言:阮老师第一个例程里面的<script type="text/babel"> 貌似写错了
<script type="text/jsx">
// ** Our code goes here! **
</script>
不太明白,应该是"text/jsx"还是"text/babel"
Diff算法解释是否已收入React中文社区http://www.laolifactory.com/index.php/2015/10/19/reacts-diff-algorithm-chinese/引用题叶的发言:留个链接, 我是 React 中文社区维护者之一(跟 Facebook 无关..).
社区交流的渠道可以在 http://nav.react-china.org/ 查看.
如果大家有兴趣追最新的消息, 交流跟分享 React, 可以细看一下.
引用Leo的发言:那是转换成 原生 js 后, 才不用添加的吧.
现在貌似改成了0.14版本后 "text/jsx"改成"text/babel" ,官方不再发布 JSXTransformer.js 了 改成babel解析...
http://www.tuicool.com/articles/NFvYfeB
Demo2 控制台报错
Each child in an array or iterator should have a unique “key” prop
解决办法只要在循环的每个子项添加一个key就行了,代码如下:
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
{
names.map(function (name, key) {
return Hello, {name}!
})
}
,
document.getElementById('example')
);
这些东西,花一天时间看一遍官方文档就都知道了好吧。。还看了几个月。。。
为啥这里可以直接写 onClick={this.handleClick} ? 而不是this.handleClick.bind(this)
在DOM4中,HelloMessage是自定义的吗,还是react中有规定,另外如果是自定义的话那首字母必须大写吗,因为我试了下,如果首字母小写的话是不报错,但是也没显示出来,所以这里的名字是自定义,但是首字母必须大写的对吗老师
阮大哥好用心,react 0.14 才出来一个月,这个教程已经更新了,用上了 ReactDOM
四:添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
试了一下,属性class和for都可以在页面上输出,代码(html忘记转义了,再发一次):
var HelloMessage = React.createClass({
render: function() {
return <div>
<p>HelloMessage组件属性</p>
<p>name: {this.props.name}</p>
<p>date: {this.props.date}</p>
<p>class: {this.props.class}</p>
<p>className: {this.props.className}</p>
<p>for: {this.props.for}</p>
<p>htmlFor: {this.props.htmlFor}</p>
</div>;
}
});
ReactDOM.render(
<HelloMessage name="张三" date="2015-10-30" class="icon iocn_home" for="AAA" className="BBB" htmlFor="CCC"/>,
document.getElementById('example')
);
阮老师,能不能把react结合ES6谈一谈呢,与ES5还是有点区别的。
引用pv的发言:不好意思,没有深入理解学习四:添加组件属性
确实是 class 属性需要写成 className ,for 属性需要写成 htmlFor
谢谢阮老师~
demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using
另外demo9也会报警告不要直接插入document.body.
几个月也太久了吧
我希望1个月能投入生产的
引用ZJZHOME的发言:谢谢阮老师~
demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using
另外demo9也会报警告不要直接插入document.body.
你可以参考这篇文章:虚拟DOM Diff算法解析
看了阮老师这篇文章收益匪浅!我是做客户端的,之前琢磨react native,看到jsx有点头疼,读完此篇,疑惑全解了。既然也在支付宝,也是同事了,同事中的老师!赞!
非常感谢,文章对我很有帮助,公司最近做react项目,正愁学起来麻烦,这篇绝对是超好的入门教程
良心文章啊。 随react版本变化而更新文章。
ES6版在这,https://github.com/zhuangtongfa/react-demos
求star
引用初学者的发言:现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白;
如果是移动端直接就原生写吧, 实际上也没多少代码量.
先攒一下阮一峰老师,Angularjs现在正在用,完成俩一下项目,感觉很顺,代码量少backbone和angular我认为不能比,angular的模板载入绝了,还有路由都不错感觉比react完整,适合面向对象抽像不强人用,解耦等都不错,阮一峰老师这个文章入门真好,个人认为react面向对象抽像要强才能写的好
现在的框架每一个框架都需要你学习一种语法,这个代价也大..公司换人也困难..无论它多优秀..这个成本也挺高的.
应该是react入门里面最好理解的教程了,最近找了一大圈react教程基本都是复制黏贴好坑人的,这篇绝对秒杀同类型教程
请问,您的例子如何在webstorm里面写呢,因为是html格式的,它一直报错,在js里可以正常提示jsx,如何在写html的时候还让它认识react呢?
想请教一下大神 这里面的中文乱码怎么解决?
React非常优秀,阮老师也一直非常优秀,非常好的一篇入门文章,阮老师一直出精华。
React亮点是html作为了js组件,实现了dom diff和状态机的思想。
React解决的一些问题,其实用一些简易优秀库,各取其核心,一样可以实现需求,而且开发成本也低,不会像React一样,各种查api,时间大部分都花在了看api上
但个人认为,前端开发应该简而大方,不应该被一个react或angular局限在它们的生态圈中。一年前还有很多人在追逐angular,想着统一天下,现在又开始追逐react
没有完美的框架存在。简单了,维护性才好
真心赞一个,给了我们新手不少帮助,
另外在重复一个问题,我也遇到了demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using
这个该怎么解决?
阮老师太牛逼了,所有文章都简洁易懂,学了好多知识。
我都不好意思在潜下去了。。写的好!
引用吖木的发言:五、this.props.children
function(child){
return {child}
}
这里应该是这样吧?
五、this.props.children
function(child){
return <li>{child}</li>
}
文章很棒,但预测React只叫好不叫座,不建议多看,还是应该多看ES和JQ。再牛B的框架,也绕不开浏览器的渲染机制。至于React还出了Native版的,这个纯属FB的痴心妄想了,Native的一统世界了,让安卓和iOS喝西北风去吗?
demo5应该return <li>{child}</li>;
原来阮老师这篇文章更新了啊,赞!
很好的入门教程~~~希望能有一篇文章,说说reactjs的实现原理~
阮老师,第五点 return {child}; 应该 return <li>{child}</li>
谢谢指出 Demo05已经改过来了。
引用rolin的发言:貌似this可以随便用都无视函数作用域?
this用在react内部的函数里面,比如render,由react调用肯定没问题,
this用在自定义函数里面,都要有显示绑定this,比如 onChange={this.handleChange}
引用邬畏畏的发言:我个人的感觉,JSX是需要React解析的,这种语法糖也会改变开发JavaScript的开发方式,时间久了会导致原生JavaScript不熟了,因为好多问题你要前端非常熟悉JavaScript,否则就导致漫天大海的在网上找解决方案。
我个人觉得,类似React的这种东东不要改变JavaScript写代码方式,可以在用JavaScript编写面向对象的组件上解决组件开发中单点的处理,而不是弄一套体系改变前端开发人员的开发方式。
React是可以不用JSX的,可以直接写js
jsx:Hello {this.props.name}
js:React.createElement("div", null, "Hello ", this.props.name);
主要是jsx的类html语法比起原生js容易构建用户界面,嵌套层次一多自然会去用jsx了,只是做一层预编译
Demo,做得不错
demo 9里面 handleChange 需要传递event进去,还有就是input里面value={this.state.value}
踩到了一个坑。
组件的命名:应该是首字母大写的。
习惯了驼峰命名法的coder,看到这个文章可能会果断小写,题主可否修改下?以免大家误解造成浪费时间,无法继续学习。
ps. 问了一圈得到答案后,搜索了下本页,居然很多人都发现了 - -
感谢分享时下最热的前端开发框架中文版介绍。
一直有关注阮老师的博客,可以说这个博客真正促成了我进入前端行业,感谢!
说回这篇文章,React.js 的几个核心概念都阐明得很清楚,提一点意见,只解释概念和给一些小Demo 是不够的,React.js 的使用情景是数据随时变化、模型之间互有依赖的复杂应用,其革命之处乃是在于数据单向流动的Flux 模型,初学者理解这个模型比弄清组件、传参这些概念重要得多。
组件之间是如何通信的???
当有一组按钮,
点击其中一个添加 active 样式,
其兄弟按钮,删除active样式。
这样的操作,不利用jquery或zepto这样的框架。
在react 中怎样实现呢?
您好,我在执行demo2/inde.html时,报错如下Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. See https://fb.me/react-warning-keys for more information.
虽然对页面显示没有影响,但是我想知道为何会报这样的错误,以及如何解决?
我有试着百度结果,但是最终还是没有解决,希望您能够抽空解答一下,谢谢……
关于browser 官方放了cdn 速度很不错
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
男神,能不能在多写react在实际应用的文章。或者 微博发篇0.13和0.14的区别?因为现在许多教程都是0.13的 而0.14有许变化引用就不同text/jsx也变了 我想知道为什么?
发布这么久了,才看到
看到混写js和html那就给跪了。整一个增强版的前台jsp语言。
膜拜!!
深入一点说的话,Virtual DOM中的Style要写成Object的形式是因为它的DOM-Diff算法的需要,界定add/remove操作
引用李黎的发言:您好,我在执行demo2/inde.html时,报错如下Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. See https://fb.me/react-warning-keys for more information.
虽然对页面显示没有影响,但是我想知道为何会报这样的错误,以及如何解决?
我有试着百度结果,但是最终还是没有解决,希望您能够抽空解答一下,谢谢……
由于React注重UI效率,使用Virtual DOM Diff来提高效率,最小化Html DOM渲染开销,所以遇到DOM nodelist时期望每个node有个key来做引用标识, 这仅仅是一个Warning,一般不会对你的App功能造成影响,但是应该注意此类问题,大规模View中可能会引发性能问题。
解决此问题的方法就是给你的Virtual DOM Nodelist中每个Node加唯一的key标识。
{List.map(function(item){
return (<li key={"Item-"+item.id}>{item.name}</li>);
})}
看见React的代码我都感觉好恶心。
没有我写的html页面简洁明了。
引用Nixus的发言:我有点儿贪心了:React能否开发游戏/移动端游戏?
2D交互游戏肯定是可以的
支持OOP否?比如可以写一个子类,覆盖超类的方法。
有(或将来会有)代码提示IDE插件否?
引用郑晋的发言:
React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。
已经在工作中使用了,React 上手的话还是可以的,但是真的用来做较为复杂的页面,还是要花些时间查看文档的,不是很简单。
而且,完善的功能实现的话,不会只有 React,我做的时候是参照 Flux 的架构,由于不熟悉,真的是有些费劲(这个数据流还真是不寻常....)。
通览一遍,一句话“jQuery把前端带到了极简主义,React把前端带到了复杂主义”。这些DEMO里隐隐看到的都是PHP模板渲染的东西。对,facebook就是用PHP的。把PHP做的事情换成用JS来做,还写得那么复杂,真不明白有什么意义。
引用郑晋的发言:只有组件还处于挂载状态下,才有setState从而更新视图的意义。
说通俗点,就是当组件渲染完成之后才设置组件的形态(以免get返回数据快过组件渲染速度,造成无法设置组件形态。)
因为ReactJS的大名一直如雷贯耳,所以便花了些时间了解一下。原本以为只是简单的不同于JQuery的封装,但实际上却是完全打破了以前HTML开发的模式。
看到上面一大串的拍马评论,和对那位名为“初学者”的留言用户的抨击,忍不住写下看法。
从使用HTML属性到HTML和CSS分离,再到JavaScript处理逻辑,用了不短的时间。现在很少看到杂糅着各种语言的页面代码。
所以,最初看到ReactJs代码的时候,简直不敢相信眼睛,这么多年分离的结果,又活生生地杂糅到了一起。
歪果仁的创新能力的确强,前端这点东西折腾出了很多新的花样。但是FB的东西,实在是不敢说都是能改变世界的东西。FB为了让PHP更快用HHVM,脱离标准PHP。是的,他们的确是可以做到,很牛逼。但是这样真的好吗?最新的PHP7已经面世,打脸一般地证明了标准PHP同样可以很快。
ReactJS混合了JS代码和HTML代码,其实它只想做一件事情,那就是组件化前端。但是组件化前端真的有必要用这么极端和不优雅的实现方式么?JS的地位如今已经被哄抬到了一个它设计之初都没想到的位置。以至于为了坐上王位,JS必须用它不算坚固的权杖,支撑起自己。JS的语法结构根本很难以这样无限制的拓展和包容一切。
ReactJS概念的确是新颖,但是这不代表它就一定比分离代码和显示的模版优秀。组件化就代表着可复用?组件化就意味着可工程化。分离的模版就没法复用,没法工程化?
最大的一套说辞往往就是“未来的页面会日趋复杂”,真相真的是这样吗?不得不承认,现今的互联网页面的确是比二十年前的页面复杂,但是页面再复杂,也终究是有极限的。简单的设计风格已经逐渐成为设计潮流,复杂的页面难道没有又逐渐变简单的趋势吗?除了淘宝这类电商的页面复杂无比外,还有多少网站是需要极其复杂的动态前端。
越是简单的页面越是能让用户易于理解和提高更好体验不是吗?至于什么丰富的交互,革命性体验,ReactJS和普通前端架构又有什么区别。
组件化可维护性很强,的确,从名称上看起来就有很强维护性。现在后端的代码也是所谓的组件化,甚至各种设计模式的应用,放到现实中的项目,真的能说“可维护性”很强吗?
传统前端所见即所得,我思即我需,应该更为贴近人类思想,这不正是编程语言所一直努力的方向么。
未来前端肯定会有更好的方向和发展,但绝对不会是ReactJS。
@Cheny:
感觉你说的有一定的道理,但是ReactJS能走多远,得用时间去验证和大家的认同
问一句,如果我有一个想重复使用的组件,如果组件定义的代码放在一个单独的js文件里。
多个页面的多个地方要使用这个组件,有什么办法吗?
刚开始学习这个东西,也只是研究性质的,貌似组件的定义和组件的渲染一定要写作一起,不能独立开来的。
//定义
var SingleArticle = React.createClass({
render: function() {
return (
SomeArticle
);
}
});
//渲染
ReactDOM.render(React.createElement(SingleArticle, null),
document.body);
还有,在式样定义上也觉得蛮奇葩的,JSX不走标准化路线,可能学了之后,没有其他使用的地方。
React Native还是算了吧,开发Native的程序的成本现在也很低了。
文章中对于onClick的处理,没有这样写:this.handleClick.bind(this) 而是直接 this.handleClick()的话,会不会有this在调用时被改变的错误发生?谢谢
你好,我下载的0.14版本中没有了browser.min.js?该怎么将JSX 语法转为 JavaScript 语法?
@奋斗:
browser.min.js是Babel提供的。可以就只用Demo里面的版本。
帅的不能再帅了!!!给您大大的满分!!!
非常浅显易懂,赞
你的blog我一直在看
引用Yuan25的发言:文章中对于onClick的处理,没有这样写:this.handleClick.bind(this) 而是直接 this.handleClick()的话,会不会有this在调用时被改变的错误发生?谢谢
this.handleClick(); 这里可以这些写,简单说的话是因为这里其实会被解析转换(注意所有的代码写的是jsx,既不是js也不是html,当然最终是会被解析成js),底层还是会调用bind(this)或类似的方式绑定正确的this。
大神您好!本人初学前端;想请教下,demo10的bind(this)的用法,如果我把这个去掉,系统就会报错:
Uncaught TypeError: Cannot read property 'opacity' of undefined
想问下,这里为什么是这样写的呢?
期待回复,谢谢
引用路人甲的发言:文章很棒,但预测React只叫好不叫座,不建议多看,还是应该多看ES和JQ。再牛B的框架,也绕不开浏览器的渲染机制。至于React还出了Native版的,这个纯属FB的痴心妄想了,Native的一统世界了,让安卓和iOS喝西北风去吗?
你的“预测”在你预测的时间点已经是伪命题。JQ 说的是 jQuery 吗。。。。?这个应该多看?。。。。呵呵呵呵呵呵
this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));
这个没看懂,this.props.promise.then是什么意思?
写的比官方教程清晰多了,可以简单入门,很有帮助,感谢阮老师~
谢谢阮老师
受益匪浅!多谢阮一峰老师!
引用锋的发言:this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));这个没看懂,this.props.promise.then是什么意思?
.then()是jquery的方法,参数(success(),error())
=>是es6语法,我理解为
componentDidMount() {
this.props.promise.then(
function(value){this.setState({loading: false, data: value})}.bind(this),
function(error){this.setState({loading: false, error: error})}.bind(this)
)
}
受益匪浅!多谢阮一峰老师!每篇文章都是精华。
阮一峰老师:
var HelloReact = React.createClass({
propTypes:{
title: React.PropTypes.string.isRequired
},
render:function() {
return <h1>{this.props.title}</h1>
}
});
var data = function () {console.log(1);};
var data1 = "ss";
ReactDOM.render(
<HelloReact title={data} />,
document.body
)
这个验证为什么不会报错?
访问react的网页,是不是必须把react.js,react-dom.js,browser.min.js这三个文件下载到客户端才能运行,这几个文件还挺大的,如果真是这样岂不是很影响性能和用户体验?有没有靠谱的解决方法呢
太厉害了,拜读
@Cheny:
同意。
大公司或许可以使劲折腾,小公司还是要多考虑软件的可维护性。
越复杂的东西就越难维护,js+html的模式,对一般开发来说不见得是好事。
或许未来等React更成熟,更优雅,坑填的差不多了,这种模式就流行了。
谢谢教程的帮助,前端学习中,甚至有冲动自己写一个框架。js+html对css提供更好的对接方式,让开发更快。
请问,什么叫“组件类只能包含一个顶层标签”?
学习组件话,先看看 老师的入门一下~
感觉和qt,friemonkey类似,只不过使用的技术更亲近web开发
说实话,目前react是最靠谱的web ui组件化方案了。
1.React的组件化才是web ui部件的正确方向
1.1.组件化集成html ,css,js自我包含一体化,方便复用。
不鼓励使用mvc模式。或者组件内部使用mvc来分离ui与js,但整个page页面是不提倡mvc的。。
1.2.相比angular。Js方便好用
2.React的问题与改进:
2.1. 可视化模板不容易得到dw的支持。。
作为模版,得到类似dw 这类可视化Html ide的支持的是必须的。。
改进建议:使用html文件作为组件,小型组件可以使用ajax读取载入,这样组件可以方便dw的设计。。大型组件可以使用ajax载入,也可以iframe方式载入。。
2.2.组件的html与js的集成是以js为基础的
这导致了界面可视化设计极差。。应该以html dom为基础,在html的基础上内嵌js。。Js本身就是代码,可视化要求相对较低。。Dom 标签使用常用的class 增加一个特点的oocss class来表明一个组件的类型,以及复合组件,或者可增加一个扩展属性。。
2.3.组件的属性以js为主
这带来查看属性值的调试的问题,如果可以在html标签上扩展属性,就方便调试,毕竟浏览器查看工具可以一目了然的查看属性的值
demo13怎么玩的,
请问如果定义 var MyButton = React.createClass({...})放在单独文件里比如 abc.js
html页面引用 <script type="text/babel" src="js/abc.js"></script>
页面来定义在哪里渲染(其实为了重用),页面调用:
<script type="text/babel">
ReactDOM.render(
<div><MyButton text="sure2"/></div>,
document.getElementById('content')
);
</script>
为什么不行?
Uncaught ReferenceError: MyButton is not defined
写的很好.学起来很容易.
比那些什么鬼视频讲的好多了
一目了然, 虽然现在只是大致看了一下 没有一个个demo去尝试着做,
但是的确比其他教程要好得多!
太棒了,清晰明了,受益匪浅
由浅入深,大赞
React个人感觉还是挺简单的。很喜欢阮老师的文章,写的很细致。
学习了,非常感谢!!!
写的非常好,自己琢磨好长时间,没有太懂,来这看了一个晚上,收获很多!非常感谢!
回过头来看,真的不错,
组件化,这个发展的趋势有点像Flex!
感觉前端的发展就是大家在制定一套界面设计的DSL,看谁更经济。
求教啊,在做项目时候,要发布上服务器,broswer.js很大,我用react-tool 把jsx的组件文件转化成了js文件,然后移除了browser.js的引用,页面渲染不出来啊?难道不能缺少browser.js吗?
感觉vue跟react好像
好用,点赞,很好的入门实例,对react有了大概了解,谢谢。
Web的问题是否能够依靠"组件化"来解决是需要讨论的?但现在出现的现象,是我们过于关注技术本身,而忽略了Web自身的特性。如此众多的组件库和框架都试图证明自己是解决Web的不二法则,有注重服务器端解决方案的,例如
* Tag library - Struts Tag
* Template Engineer - Velocity, Freemaker
* Components: Awt/Swing, JSF
有关注客户端的解决方案的,例如
* Flash, Applet
* java-script library: YUI, Dojo
* java-script framework: Angular, EmberJs, Rect.js
那么什么是Web的实质呢?它原本只是用来展现数据的载体,至于什么方式或者方法其实是无所谓,你用Struts Tag也好用Dojo也好,都只是为"展示"这个动作服务的。过分的关注工具的使用,而忽略了技术之外的东西(比如Dom, CSS, javascript语言这些本身的特点)就本末倒置了。
玩玩新东西还是可以的,但个人感觉这种写代码方式会扰乱正常js的写法方式,有的时候学得越多越混,到头来写简单的js都犯低级错误是得不偿失的。
引用郑晋的发言:只有组件还处于挂载状态下,才有setState从而更新视图的意义。
我还是有疑问,componentDidMount已经是渲染完成了,这就证明组建已经肯定是处于mounting状态的。$.get(url,function)这里的function是成功后的回调,也就是说,数据已经返回了。
1、组件状态是mounting状态。
2、数据已经返回。
为什么还要判断isMounted()?
引用业界大牛的发言:由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。
props,在这里很常见的用法是传参,显然形参你改了也灭用
而state这个属性就要好好把玩了,也说了,交互中很常见的状态
怎么感觉你是 => 张鑫旭大师呢
demo13 npm install 安装后运行node server.js还是报错,应该是jsx编译报错
报错信息是
E:\www\myTest\react-demos-master\demo13\src\server.js:20
<body>
^
SyntaxError: Unexpected token <
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:968:3
烦问这是什么原因?试过直接安装babel-core 和 babel-cli也不行
@spring:
看demo13的README,需要 npm run build。
引用阮一峰的发言:@spring:
看demo13的README,需要 npm run build。
哇喔,果然,谢谢偶像
我们这项目 要用 React和OnSen UI开发 苦苦找了很多 看的 很痛苦 !
当我看到您分享的 入门很快,谢谢
希望有些深入React 见解 案例 分享下
谢谢!!!!
引用郑晋的发言:只有组件还处于挂载状态下,才有setState从而更新视图的意义。
可是componentDidMount()不就是视图挂载后才响应的事件吗?
歪果仁奇思妙想,果仁跟风。
1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?
引用cristal000o的发言:1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?
你可以搜索下js的bind用法
引用cristal000o的发言:1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?
setInterval()内部的this指向window,而我们需要当前的对象,故绑定this传入。
引用cristal000o的发言:1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?
忘了说,bind()是ES5的方法,所以想兼容浏览器,需要自己写一个bind()函数。
老師,
我練習完你的範例之後,
試著將組件拆成外部一個個的js檔後發現就報error,
我也試著上網查了相關的教學,
發現大家的教學好像都是將組件寫在同一隻js或是html中,
不知道如果是以下的結構要怎麼樣往外拆?
遠本寫在index.html中的js
var Test = React.createClass({
render: function () {
return (
Test
);
}
});
ReactDOM.render(
,
document.getElementById('main')
);
想要改成link:
刚一打开页面感觉好长一篇,看完才发现下面都是评论。。。
@Cheny:
层住观点我比较赞同,框架这东西仁者见仁智者见智,不是流行的就是好的,适合自己就好
今天再来看的,react生态是最复杂的引用郑晋的发言:
React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。
最初看到您的文章觉得写的也不错,但是并没有出彩的地方(个人愚见)!直到今日学习react,看了好多教程,包括官方英文的教程,皆不能得其要领!直至看到阮老师的react文章,一句话真是对我醍醐灌顶,帮助甚大,特此鸣谢!!!
引用rolin的发言:貌似this可以随便用都无视函数作用域?
初代版本有做 this 作用域的封装~
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求, 这里应该是propType,应该是小写开头的。
@Cheny:
严重赞同!真不觉得“初学者”说的有错,代码维护连续性,确实存在这些问题。不能从正面解决问题出发,除了打击、抨击,显得高高在上,很爽?!
您好,我在使用最新的react开发的过程中发现无法使用ReactDOM.findDOMNode这个方法;有什么解决办法呢
React是facebook的项目,然而他们的老大,马克扎尔伯格不是说过自己投资HTML5是极大的失败吗?那我很好奇他对于HTML5相关的项目或者技术的支持力度能有多大,或者说有多久?
一个框架,不是要看它一时的风光,而是未来的可维护性。jQuery为何能够生存十年还屹立不倒?这离不开数万个程序员的你一字我一句的代码维护。
如果真的要制作MVC框架,其实Angular就是个很好的选择了吧,至少人家在1.X版本风靡的前提下,胆敢大刀阔斧的推出2.X版本,这本身就说明了这个团队的精益求精。
此外,项目也必须考虑到后续的维护呀,如果现在用的是昙花一现的框架,那么接手的人遇到了问题,想在网上找个解决方案都不太容易,总不能让他们重新制作一个网站吧?
当然,以上的言论并没有针对阮老师的意思,阮老师对于我而言,是新兴技术的一盏明灯。
只是觉得有些人只顾追逐时尚潮流,却不顾框架/技术是否适合自己适合团队,是否具有可维护性就去讥讽他人,这种行为不太雅观。
求推荐react与现有项目结合的文章
引用happyChong的发言:求推荐react与现有项目结合的文章
同求
引用瀚海的发言:React是facebook的项目,然而他们的老大,马克扎尔伯格不是说过自己投资HTML5是极大的失败吗?那我很好奇他对于HTML5相关的项目或者技术的支持力度能有多大,或者说有多久?
如果真的要制作MVC框架,其实Angular就是个很好的选择了吧,至少人家在1.X版本风靡的前提下,胆敢大刀阔斧的推出2.X版本,这本身就说明了这个团队的精益求精。
1.React不是MVC框架,它只能算是MVC中的V
2.Angular1.x和2.x完全是两个不同的框架,也没给出迁移方案,太坑了(2.x)!
3.我们只有对框架的深入理解后,才能为项目技术的选型提供很好的保障
把官方的文档看完,再看这个也是很有收获
正因为追求极致,才推进了前端行业的蓬勃发展。丰富的交互,革命性体验,ReactJS确实比其他普通前端架构更好,特别是移动端,甩Angular几条街。虚拟dom这一概念提高了web性能,部分其它类似的框架都是直接操作DOM,这点不得不服。单看fps,实际测试react在51-60fps, h5在33-55fps。
还有native方面,追求App和wap的统一,react提供了目前最好的方式。
当然实际开发项目里,不只有react,还有和他相关的好多,比如redux,router,为了追求极致,你还可以再上immutable.js。react实现了完全的前后端分离,国内目前也有好多再用了。
颠覆了传统的前端行业,目前在学习,着实惊叹!!!
新兴技术自然有它的优势,太多人不愿花额外的学习成本去了解它,就开始喷了。说啥维护性不好,说啥别人都是跟风,竟然还有人固守jQ,没有学习永远不会有成长。
老师的文章除了Flex篇 其他都是精髓
哪位有测过demo06,为什么我的没报错,正常输出数字?
只想说一句谢谢!
引用码字所得税的发言:哪位有测过demo06,为什么我的没报错,正常输出数字?
我也是。。。
this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));
请问这段代码是什么意思呢?有什么地方可以深入研究
老实说,初看react这样的代码风格,非常恶心,强迫症患者是在是受不了那种代码无依无靠的感觉
我要发表看法
阮一峰的网络日志 » 首页 » 档案分类:
React 入门实例教程
现在最热门的前端框架,毫无疑问是 React 。
上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。
由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。
这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。
既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 React 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 React 本身还在不断变动,API 一直在调整,至今没发布1.0版。
我学习 React 时,就很苦恼。有的教程讨论一些细节问题,对入门没帮助;有的教程写得不错,但比较短,无助于看清全貌。我断断续续学了几个月,看过二十几篇教程,在这个过程中,将对自己有帮助的 Demo 都收集下来,做成了一个库 React Demos 。
下面,我就根据这个库,写一篇全面又易懂的 React 入门教程。你只需要跟着每一个 Demo 做一遍,就能初步掌握 React 。当然,前提是你必须拥有基本 JavaScript 和 DOM 知识,但是你读完就会发现,React 所要求的预备知识真的很少。
零、安装
React 的安装包,可以到官网下载。不过,React
已经自带 React 源码,不用另外安装,只需把这个库拷贝到你的硬盘就行了。
Demos
$ git clone git@github.com:ruanyf/react-demos.git
如果你没安装 git, 那就直接下载 zip 压缩包。
下面要讲解的12个例子在各个 Demo
子目录,每个目录都有一个 index.html
文件,在浏览器打开这个文件(大多数情况下双击即可),就能立刻看到效果。
需要说明的是,React 可以在浏览器运行,也可以在服务器运行,但是本教程只涉及浏览器。一方面是为了尽量保持简单,另一方面 React 的语法是一致的,服务器的用法与浏览器差别不大。Demo13
是服务器首屏渲染的例子,有兴趣的朋友可以自己去看源码。
一、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
节点(查看 demo01
),运行结果如下。
三、JSX 语法
上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写(查看 Demo02
)。
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 变量。如果这个变量是一个数组,则会展开这个数组的所有成员(查看 demo03
)。
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 方法就用于生成一个组件类(查看 demo04
)。
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
组件包含了两个顶层标签:h1
和p
。
组件的用法与原生的 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
属性。它表示组件的所有子节点(查看 demo05
)。
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
。更多的 React.Children
的方法,请参考官方文档。
六、PropTypes
组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes
属性,就是用来验证组件实例的属性是否符合要求(查看 demo06
)。
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`.
更多的PropTypes
设置,可以查看官方文档。
此外,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
属性(查看 demo07 )。
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
、Copy
、Scroll
等,完整的事件清单请查看官方文档。
八、this.state
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08
)。
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
读取(查看 demo9
)。
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):组件判断是否重新渲染时调用
这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10
)。
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 (查看 demo11
)。
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's official site
- React's official examples
- React (Virtual) DOM Terminology, by Sebastian Markbåge
- The React Quick Start Guide, by Jack Callister
- Learning React.js: Getting Started and Concepts, by Ken Wheeler
- Getting started with React, by Ryan Clark
- React JS Tutorial and Guide to the Gotchas, by Justin Deal
- React Primer, by Binary Muse
- jQuery versus React.js thinking, by zigomir
(完)