这段时间公司需要用到react+python来进行web开发,这不,上两个礼拜一直在学react和python相关知识,做出了一个小的demo-在线多人聊天室。对上面两种技术从无到有的理解,在做的过程中,也遇到了许许多多问题。虽然感觉基本入门了,但是感觉仍然需要来回顾一遍基础,这样能够更好的掌握。
这篇博文主要是个人对网上知识以及书上知识的总结。
什么是React?
- React 是一个用于构建用户界面的 JAVASCRIPT 库。
- React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)
- React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
- React 拥有较高的性能,代码逻辑非常简单
其实到这里,可能对React的理解,就是一个js库嘛,根jquery一样都是个js库嘛,其实不然。
下面看react的特点吧:
- 声明式设计 −React采用声明范式,可以轻松描述应用。
- 高效 −React通过对DOM的模拟,即React操作的是一个虚拟DOM,而不是真实DOM,最大限度地减少与DOM的交互。
- 灵活 −React可以与已知的库或框架很好地配合。
- JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
- 组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
- 单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
看了上面的特点,就感觉和jquery不同了吧,jquery更向一个工具包,而React才是一个真正的框架。
在React里面,你可以封装组件,然后这个组件就是一个component,你可以把这个component像html标签一样的使用。后面会讲关于这个component。
另外一个特点就是jsx,jsx可以看作javascript的扩展,里面可以随意嵌套html语言。
由于是组件式的思维,所以当你一个component数据变化时候,需要重新渲染的,也只是你这个component,而不会牵扯到其他component。
如何开始使用React
一、在线直接引用:
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
二、通过npm安装
npm是nodejs里面一个工具,其实npm就像Java里面的maven,或者python里面的pip,专门用来管理引用包的。
国内使用 npm 速度很慢,你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
$ npm config set registry https://registry.npm.taobao.org
然后:
$ cnpm install [name]
然后在js里面这样引入:
import React,{ Component } from 'react';
就可以在js使用React了。
ReactDOM.render()方法
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
另外,每个component里面都会有一个render方法,这个方法就是用来渲染这个组件的,每当组件state改变时候,就会触发这个方法。
例如这个很简单的例子:
<div id="example"></div>
<script type="text/babel"> ReactDOM.render( <h1>Hello,world!</h1>,document.getElementById('example') ); </script>
React JSX
- jsx是一种扩展的js文件,里面可以包括js代码,也可以嵌入HTML代码。
- JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。
- JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员
上面是jsx的基本特性,下面则是一些具体用法注意事项:
在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代
例如:
ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>,document.getElementById('example')
);
注释需要写在花括号中,实例如下:
ReactDOM.render(
<div>
<h1>anLA的博客</h1>
{/*注释...*/}
</div>,document.getElementById('example')
);
React渲染html组件和React组件方式:
要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。
var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement,document.getElementById('example'));
要渲染 React 组件,只需创建一个大写字母开头的本地变量。
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement,document.getElementById('example'));
React State(状态)
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态(也就是改变当前component的state的值),然后由于render方法里面有引用state的值,所以会自动调用render方法,进而渲染 UI,让用户界面和数据保持一致。这样以来,不需要程序员自己去操作DOM
React Props
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
props的基本用法:
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<HelloMessage name="Runoob" />,document.getElementById('example')
我们知道,html
标签有属性,例如img
标签的src
属性,a
标签的href
属性等,同样在React自定义组件里面,也有属性,在render方法之外,我们可以通过this.props.name
来获得。
props属性的验证:
另外,我们也可以利用propTypes来对props进行验证,当react检测到验证不通过时候,就会在console中报错:
var title = "anLA的博客";
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isrequired,},render: function() {
return <h1> {this.props.title} </h1>;
}
});
ReactDOM.render(
<MyTitle title={title} />,document.getElementById('example')
);
当然不同需求的验证还有很多,这里就不一一列出来了。
props和state之间传递数据:
什么意思呢?先看一个简单例子:
var WebSite = React.createClass({
getInitialState: function() {
return {
name: "anLA的CSDN博客",site: "http://blog.csdn.net/anla_"
};
},render: function() {
return (
<div>
<Name name={this.state.name} />
<Link site={this.state.site} />
</div>
);
}
});
var Name = React.createClass({
render: function() {
return (
<h1>{this.props.name}</h1>
);
}
});
var Link = React.createClass({
render: function() {
return (
<a href={this.props.site}>
{this.props.site}
</a>
);
}
});
ReactDOM.render(
<WebSite />,document.getElementById('example')
);
对于Name和Link这两个组件来说,WebSite是他们的父组件,这个时候,按照编程习惯,都是在父组件里面传值,所以就定义了state的两个值,anLA的博客
以及http://blog.csdn.net/anla_
这个时候呢,当然子组件得拿的到这两个值,所以在子组件中利用this.props.site
来获取值.
我们可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中,我们设置 name 和 site 来获取父组件传递过来的数据。
React组件API
React组件分不同的类别主要有以下几种API:
- 设置状态:
setState(object nextState[,function callback])
- 替换状态:
replaceState(object nextState[,function callback])
- 设置属性:
setProps(object nextProps[,function callback])
- 替换属性:
replaceProps(object nextProps[,function callback])
- 强制更新:
forceUpdate([function callback])
- 获取DOM节点:
DOMElement findDOMNode()
- 判断组件挂载状态:
bool isMounted()
几个注意的地方:
关于setState
- 不能在组件内部通过this.state修改状态,因为该状态会在调用setState()后被替换。
- setState()并不会立即改变this.state,而是创建一个即将处理的state。 - setState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。
- setState()总是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。
- replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
关于props:
props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。当和一个外部的JavaScript应用集成时,我们可能会需要向组件传递数据或通知React.render()组件需要重新渲染,可以使用setProps()。更新组件,我可以在节点上再次调用React.render(),也可以通过setProps()方法改变组件属性,触发组件重新渲染。
关于forceUpdate:
forceUpdate()
方法会使组件调用自身的render()
方法重新渲染组件,组件的子组件也会调用自己的render()。但是,组件重新渲染时,依然会读取this.props
和this.state
,如果状态没有改变,那么React只会更新DOM。
forceUpdate()
方法适用于this.props
和this.state
之外的组件重绘(如:修改了this.state后),通过该方法通知React需要调用render()
一般来说,应该尽量避免使用forceUpdate(),而仅从this.props和this.state中读取状态并由React触发render()调用。
React组件的声明周期
按照被加载的的过程来分,React主要包括以下几个声明周期:
componentWillMount()
:在渲染前调用,在客户端也在服务端。componentDidMount()
: 在第一次渲染后调用,只在客户端。之后组 件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout,setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)。componentWillReceiveProps(newProps)
: 在组件接收到一个新的prop时被调用。这个方法在初始化render时不会被调用。shouldComponentUpdate(newProps,newState)
: 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。componentWillUpdate(nextProps,nextState)
:在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。componentDidUpdate(prevProps,prevState)
: 在组件完成更新后立即调用。在初始化时不会被调用。componentWillUnmount()
:在组件从 DOM 中移除的时候立刻被调用。React与表单事件
在下例总,设置了输入框 input 值value = {this.state.data}。在输入框值发生变化时我们可以更新 state,即重新渲染一遍。可以使用 onChange 事件来监听 input 的变化,并修改 state。
前面已经讲过,父组件的state状态,可以通过共享给子组件,方法就是子组件通过this.props.name
去获取,这里可以获取变量也可以获取函数。
var HelloMessage = React.createClass({
getInitialState: function() {
return {value: 'Hello Runoob!'};
},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} />
<h4>{value}</h4>
</div>;
}
});
ReactDOM.render(
<HelloMessage />,document.getElementById('example')
);
React Refs获取真实DOM
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。当然你的组件要新加一个ref属性。
例如下面例子:
var MyComponent = React.createClass({
handleClick: function() {
// 使用原生的 DOM API 获取焦点
this.refs.myInput.focus();
},render: function() {
// 当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
return (
<div>
<input type="text" ref="myInput" />
<input
type="button"
value="点我输入框获取焦点"
onClick={this.handleClick}
/>
</div>
);
}
});
ReactDOM.render(
<MyComponent />,document.getElementById('example')
);
最后,还有几点需要注意的地方:
- 组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。
- 组件类只能包含一个顶层标签,否则也会报错。
- this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点
- 组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。