React 是一个用于构建用户界面的 JavaScript 库,主要用于构建 UI,而不是一个 MVC 框架,但可以使用 React 作为 MVC 架构的 View 层轻易的在已有项目中使用,它是一个用于构建用户界面的 JavaScript 库,起源于 Facebook 的内部项目,用来架设 Instagram 的网站,于 2013 年 5 月开源。
1.声明式设计 −React采用声明范式,可以轻松描述应用。
2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
3.灵活 −React可以与已知的库或框架很好地配合。
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
codepen
编写Staticfile CDN
的 React CDN
库
Hello, world!
:
Hello React!
环境要求: Node>= 10.16 和 npm >= 5.6
使用 create-react-app 快速构建 React 开发环境
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start // 运行本地服务
在浏览器中打开 http://localhost:3000/
就能看到运行结果。
my-app/
README.md
node_modules/
package.json
.gitignore
public/
favicon.ico
index.html
manifest.json
src/
App.css
App.js
App.test.js
index.css
index.js
logo.svg
manifest.json
指定了开始页面 index.html
,一切的开始都从这里开始,所以这个是代码执行的源头。
ReactDOM.render
是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
ReactDOM.render(
Hello, world!
,
document.getElementById('example')
);
上面代码将一个 h1 标题,插入 example 节点.
首先我们在一个 HTML 页面中添加一个 id=“example” 的,如下:
React 开发应用时一般只会定义一个根节点。
要将React元素渲染到根DOM节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
const element = Hello, world!
;
ReactDOM.render(
element,
document.getElementById('example')
);
React 元素都是不可变的。当元素被创建之后,你是无法改变其内容或属性的。
目前更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法,比如下面这个定时器:
function tick() {
const element = (
Hello, world!
现在是 {new Date().toLocaleTimeString()}.
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick, 1000);
>
中,而不是()
key、value
时直接传递的,而不是对象格式的date数据 ReactDOM.render(
< functionname property1 = {property1_value} property2 = {property2_value} />,
document.getElementById('example')
);
以下实例用一个函数来表示前面的定时器封装:
function Clock(props){
return (
Hello, {props.name} ~
现在是北京时间 {props.date.toLocaleTimeString()}
)
}
function tick() {
ReactDOM.render(
< Clock date={new Date()} name={'world'} id={'world'}/>,
document.getElementById('example')
);
}
setInterval(tick, 1000);
值得注意的是 React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
需要注意的是在 render()
方法中,需要使用this.props
替换 props
,示例:
class Clock extends React.Component{
render(){
return(
Hello, {this.props.name} ~
现在是北京时间 {this.props.date.toLocaleTimeString()}
)
}
}
function tick() {
ReactDOM.render(
< Clock date={new Date()} name='world' id='world'/>,
{/* new Date() 这样的value,需要使用花括号来包含,仅字符串的值则不需要 */}
document.getElementById('example')
);
}
setInterval(tick, 1000);
既然这里提到了jsx,那就顺便了解一下两者的区别:
JavaScript
,一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于浏览器客户端的脚本语言。JavaScript XML
——一种在React组建内部构建标签的类XML语法。(增强React程序组件的可读性)。Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。React 实例
ReactDOM.render(
React JSX
欢迎学习 React jsx
这是一个很不错的 JavaScript 库!
,
document.getElementById('example')
);
ReactDOM.render(
hello, world
,
document.getElementById('example')
)
text/babel
):
注意:
script
标签的type
属性为text/babel
。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用JSX
的地方,都要加上type="text/babel"
。
ReactDOM.render(
{1+1}
,
document.getElementById('example')
);
ReactDOM.render(
{i == 1 ? 'True!' : 'False'}
,
document.getElementById('example')
)
React 推荐使用内联样式。我们可以使用 camelCase 小驼峰
语法来设置内联样式. React 会在指定元素数字后自动添加 px
,如font-size
要写成fontSize
:
let myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
hello, world {1+1}
,
document.getElementById('example')
)
注释需要 写在花括号{} 中,实例如下:
ReactDOM.render(
hello, world {1+1}
{/*这是注释部分*/}
,
document.getElementById('example')
)
JSX 允许在模板中插入数组,数组会自动展开所有成员:
let arr = [
React教程
,
学的不仅是React,学的是方法。
,
];
ReactDOM.render(
{arr},
document.getElementById('example')
)
function HelloMessage(props) {
return Hello {props.name}!
;
}
const element = ;
ReactDOM.render(
element,
document.getElementById('example')
);
注意:
自定义的 React 类名以大写字母开头
,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。className
,for 属性需要写成htmlFor
,这是因为 class 和 for 是 JavaScript 的保留字。直接看例子吧:
function Name(props){
return 网站名称:{props.name}
}
function Url(props){
return 网站地址:{props.url}
}
function Nickname(props){
return 网站小名:{props.nickname}
}
function App(){
return (
)
}
ReactDOM.render(
,
document.getElementById('example')
);
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass
方法就用于生成一个组件类
let HelloMessage = React.createClass({
render: function (){
return hello, {this.props.name}!
}
})
ReactDOM.render(
,
document.getElementById('example')
);
注:react最新版本弃用了 React.createClass这个函数,可以使用15.x版本尝试。
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。
挂载
。卸载
。我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {date: new Date()}
}
componentDidMount(){
let _this = this;
this.timerID = setInterval(function (){
_this.tick()
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
tick(){
this.setState({
date: new Date()
})
}
render(){
return(
Hello, world!
现在是北京时间:{this.state.date.toLocaleTimeString()}
)
}
}
ReactDOM.render(
,
document.getElementById('example')
);
实例解析:
componentDidMount()
与 componentWillUnmount()
方法被称作生命周期钩子。DOM
后会执行 componentDidMount()
钩子,我们就可以在这个钩子上设置一个定时器。setState()
,React 知道状态已经改变,并再次调用 render()
方法来确定屏幕上应当显示什么。 这一次,render()
方法中的 this.state.date
将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。this.timerID
为定时器的 ID
,我们可以在 componentWillUnmount()
钩子中卸载定时器。父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 Clock 的属性、亦或手工输入:
function FormattedDate(props){
return 现在是北京时间:{props.date.toLocaleTimeString()}
}
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {date: new Date()}
}
componentDidMount(){
let _this = this;
this.timerID = setInterval(function (){
_this.tick()
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timerID)
}
tick(){
this.setState({
date: new Date()
})
}
render(){
return(
Hello, world!
)
}
}
function App(){
return(
)
}
ReactDOM.render(
,
document.getElementById('example')
);
这里我还没有完全理解它的含义!
state
和 props
主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。
前面的示例中都已经涉及到Props的使用,这里不再举例,只再提示一点普通类和ES6 class使用上的差别:
props.name
方式访问属性this.props.name
方式访问属性例:在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据
class Book extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'react',
time: '2013年5月',
}
}
render() {
return (
)
}
}
class Name extends React.Component {
render(){
return(
Book name: {this.props.name}
)
}
}
class Time extends React.Component {
render(){
return(
Book create time: {this.props.time}
)
}
}
ReactDOM.render(
,
document.getElementById('example')
)
React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库。 React v15.5 版本以上使用时需要引入:
Props 验证使用 propTypes
,它可以保证我们的应用组件被正确使用,React.PropTypes
提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
React 16.4 实例:
var title = "react learner";
class MyTitle extends React.Component {
render() {
return (
Hello, {this.props.title}
);
}
}
MyTitle.propTypes = {
title: PropTypes.string
};
ReactDOM.render(
,
document.getElementById('example')
);
MyComponent.propTypes = {
// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 可以被渲染的对象 numbers, strings, elements 或 array
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),
// 特定 shape 参数的对象
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!');
}
}
}
}
React 事件绑定属性的命名采用驼峰式写法
,而不是小写。
在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确使用 preventDefault
。
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('链接被点击');
}
return (
点我
);
}
通常我们会为事件处理程序传递额外的参数。例如,若是 id 是你要删除那一行的 id,以下两种方式都可以向事件处理程序传递参数:
通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面,例如:
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件对象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
hello
{/* 通过 bind() 方法传递参数。 */}
Click
);
}
}
bind()
是Function对象内建的方法,它们的第一个参数都是用来更改调用方法中this的指向
。添加元素变量帮助你有条件的渲染组件的一部分,而输出的其他部分不会更改。
function UserGreeting(props){
return 欢迎回来~
}
function GuestGreeting(props){
return 请先登录~
}
function Greeting(props){
const isLogging = props.isLogging
if(isLogging){
return
}
return
}
function LoginButton(props){
return (
)
}
function LogoutButton(props){
return(
)
}
class LoginControl extends React.Component {
constructor(props) {
super(props)
this.handleLoginClick = this.handleLoginClick.bind(this)
this.handleLogoutClick = this.handleLogoutClick.bind(this)
this.state = {isLoggedIn: true}
}
handleLoginClick(){
this.setState({isLoggedIn: true})
}
handleLogoutClick(){
this.setState({isLoggedIn: false})
}
render(){
let logged = this.state.isLoggedIn
let button
if(logged){
button =
}else {
button =
}
return(
{button}
)
}
}
ReactDOM.render(
,
document.getElementById('example')
)
可以通过用花括号
包裹代码在 JSX 中嵌入任何表达式 ,也包括 JavaScript 的逻辑与 &&,它可以方便地条件渲染一个元素。示例:
function MailBox(props){
let unreadmessage = props.unreadmessage
return(
Hello!
{
unreadmessage.length >0 && 您有 {unreadmessage.length} 条未读消息。
}
)
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
,
document.getElementById('example')
);
true && expression
总是返回 expression
,而 false && expression
总是返回 false
。true
,&&
右侧的元素就会被渲染,如果是false
,React 会忽略并跳过它。用法和 JavaScript 的条件运算符一样:
condition ? true : false。
示例:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
{isLoggedIn ? (
) : (
)}
);
}
实现:让 render
方法返回 null
而不是它的渲染结果即可实现。
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
警告!
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true}
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
}
render() {
return (
);
}
}
ReactDOM.render(
,
document.getElementById('example')
);
实例:使用 map() 方法遍历数组生成了一个 1 到 5 的数字列表(每个列表元素分配一个 key
,不然会出现警告 a key should be provided for list items
,意思就是需要包含 key
:):
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map(function (item){
return {item}
});
return (
{listItems}
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
,
document.getElementById('example')
);
key
最好是这个元素在列表中拥有的一个独一无二的字符串
。function ListItem(props) {
// 对啦!这里不需要指定key:
return {props.value} ;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 又对啦!key应该在数组的上下文中被指定
);
return (
{listItems}
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
,
document.getElementById('example')
);
function Blog(props) {
const sidebar = (
{props.posts.map((post) =>
-
{post.title}
)}
);
const content = props.posts.map((post) =>
{post.title}
{post.content}
);
return (
{sidebar}
{content}
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
,
document.getElementById('example')
);
const content = posts.map((post) =>
);
function NumberList(props) {
const numbers = props.numbers;
return (
{numbers.map((number) =>
)}
);
}
setState(object nextState[, function callback])
nextState
,将要设置的新状态,该状态会和当前的state
合并callback
,可选参数,回调函数。该函数会在setState
设置成功,且组件重新渲染后调用。合并nextState
和当前state
,并重新渲染组件。setState
是Reac
t事件处理函数中和请求回调函数中触发UI更新的主要方法。
setState()
并不会立即改变this.state
,而是创建一个即将处理的state
。setState()
并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。setState()
总是会触发一次组件重绘,除非在shouldComponentUpdate()
中实现了一些条件渲染逻辑。replaceState(object nextState[, function callback])
replaceState()
方法与setState()
类似,但是方法只会保留nextState
中状态,原state不在nextState
中的状态都会被删除。
setProps(object nextProps[, function callback])
replaceProps(object nextProps[, function callback])
forceUpdate([function callback])
DOMElement findDOMNode()
bool isMounted()
组件的生命周期可分成三个状态:
生命周期的方法有:
componentWillMount
在渲染前调用,在客户端也在服务端。
componentDidMount
: 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
componentWillReceiveProps
在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate
返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
componentWillUpdate
在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate
在组件完成更新后立即调用。在初始化时不会被调用。
componentWillUnmount
在组件从 DOM 中移除之前立刻被调用。
componentDidMount() {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
}
class HelloMessage extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'Hello Runoob!'};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
var value = this.state.value;
return
{value}
;
}
}
ReactDOM.render(
,
document.getElementById('example')
);
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。
这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。
class MyComponent extends React.Component {
handleClick() {
// 使用原生的 DOM API 获取焦点
this.refs.myInput.focus();
}
render() {
// 当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
return (
);
}
}
ReactDOM.render(
,
document.getElementById('example')
);