React工作原理:
把每一个组件当成了一个状态机,组件内部通过state来维护组件状态的变化,当组件的状态发生变化时,React通过虚拟DOM技术来增量并且高效的更新真实DOM。
虚拟DOM则是在DOM的基础上建立了一个抽象层,我们对数据和状态所做的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。
React 特点:
1.声明式设计 −React采用声明范式,可以轻松描述应用。
2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
3.灵活 −React可以与已知的库或框架很好地配合。
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
首次渲染大量DOM时因为多了一层虚拟DOM的计算,会比innerHTML插入方式慢。
props 主要作用是提供数据来源,可以简单的理解为 props 就是构造函数的参数。可以通过this.props来访问props
把每一个组件都看成是一个状态机,组件内部通过state来维护组件状态的变化,这也是state唯一的作用。
JSX 做的事情就是根据 state 和 props 中的值,结合一些视图层面的逻辑,输出对应的 DOM 结构。
React JSX
- 关于React注释的问题:
1、在标签内部的注释需要花括号
2、在标签外的的注释不能使用花括号
ReactDOM.render(
/*注释 */
<h1>孙朝阳 {/*注释*/}</h1>,
document.getElementById('example')
);
- 使用 JavaScript 表达式,表达式写在花括号 {} 中:
ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
document.getElementById('example')
);
- 在 JSX 中不能使用 if else 语句,但可以使用三元运算 表达式来替代。代码中嵌套多个 HTML 标签,需要使用一个标签元素包裹它,即组件类只能包含一个顶层标签。
React 推荐使用内联样式。我们可以使用驼峰命名法来设置内联样式。React 会在指定元素数字后自动添加 px 。
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>菜鸟教程</h1>,
document.getElementById('example')
);
HTML标签vs React组件
React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。 要渲染 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 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。
注意:
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。
React组件
接下来封装一个输出”Hello World!”的组件,组件名为HelloMessage。
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello World!</h1>;
//return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<HelloMessage />,
//<HelloMessage name= “陈陈陈陈小妖” />,
document.getElementById('example')
);
React.createClass 方法用于生成一个组件类 HelloMessage。
实例组件类并输出信息。
如果我们需要向组件传递参数,可以使用 this.props 对象。 (↑修改)
注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签(需要使用一个标签元素包裹其它标签),否则也会报错。
同时,我们可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离。
var WebSite = React.createClass({
render: function() {
return (
<div>
<Name name={this.props.name} />
<Link site={this.props.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 name="陈陈陈陈小妖" site=" http://www.baidu.com"; />, document.getElementById('example')
);
注意:组件名不一定是用单标签,也可以是双标签
<HelloMessage /> == <HelloMessage></HelloMessage>
React State(状态)
React 把组件看成是一个状态机,通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
以下实例中创建了 LikeButton 组件,getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false}; //getInitialState是用来初始化state
},
handleClick: function(event) { //handleClick是用来处理点击事件
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? '喜欢' : '不喜欢';
return (
<p onClick={this.handleClick}>
你<b>{text}</b>我。点我切换状态。
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
onClick 等事件,与原生 HTML 不同,on 之后第一个字母是大写的!比如本章实例中,如果将 onClick={this.handleClick} 换成 onclick ={this.handleClick} 则点击事件不再生效。
React Props
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
可以通过 getDefaultProps() 方法为 props 设置默认值
Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
React 组件 API
设置状态:setState
setState(object nextState[, function callback])
* nextState,将要设置的新状态,该状态会和当前的state合并
* callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。
替换状态:replaceState
replaceState(object nextState[, function callback])
* nextState,将要设置的新状态,该状态会替换当前的state。
* callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。
replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
设置属性:setProps
替换属性:replaceProps
replaceProps()方法与setProps类似,但它会删除原有
强制更新:forceUpdate
forceUpdate()方法会使组件调用自身的render()方法重新渲染组件,组件的子组件也会调用自己的render()。但是,组件重新渲染时,依然会读取this.props和this.state,如果状态没有改变,那么React只会更新DOM。
获取DOM节点:findDOMNode
* 返回值:DOM元素DOMElement
如果组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当render返回null 或 false时,this.findDOMNode()也会返回null。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。
判断组件挂载状态:isMounted
* 返回值:true或false,表示组件是否已挂载到DOM中
isMounted()方法用于判断组件是否已挂载到DOM中。可以使用该方法保证了setState()和forceUpdate()在异步场景下的调用不会出错。
React生命周期:
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
React AJAX:
React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据库可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。
这是一个React组件实现组件可交互所需的流程,render()输出虚拟DOM,虚拟DOM转为DOM,再在DOM上注册事件,事件触发setState()修改数据,在每次调用setState方法时,React会自动执行render方法来更新虚拟DOM,如果组件已经被渲染,那么还会更新到DOM中去。
每个组件都有属于自己的state,state和props的区别在于前者之只存在于组件内部,只能从当前组件调用this.setState修改state值(不可以直接修改this.state)。一般我们更新子组件都是通过改变state值,更新新子组件的props值从而达到更新。
父子组件沟通
这种方式是最常见的,也是最简单的。
* 父组件更新组件状态
父组件更新子组件状态,通过传递props,就可以了。
* 子组件更新父组件状态
这种情况需要父组件传递回调函数给子组件,子组件调用触发即可。
兄弟组件沟通
当两个组件有相同的父组件时,就称为兄弟组件(堂兄也算的)。按照React单向数据流方式,我们需要借助父组件进行传递,通过父组件回调函数改变兄弟组件的props。
Flux 是什么?
Flux 是一种架构思想,专门解决软件的结构问题。它跟MVC 架构是同一类东西,但是更加简单和清晰。
首先,Flux将一个应用分成四个部分。
View: 视图层
Action(动作):视图层发出的消息(比如mouseClick)
Dispatcher(派发器):用来接收Actions、执行回调函数
Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面
Flux 的最大特点,就是数据的”单向流动”。
1. 用户访问 View
2. View 发出用户的 Action
3. Dispatcher 收到 Action,要求 Store 进行相应的更新
4. Store 更新后,发出一个"change"事件
5. View 收到"change"事件后,更新页面
Redux Redux 只是 Web 架构的一种解决方案
首先,用户发出 Action。
store.dispatch(action);
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
let nextState = todoApp(previousState, action);
State 一旦有变化,Store 就会调用监听函数。
// 设置监听函数
store.subscribe(listener);
listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
React-router
React-router的BrowserRouter(重命名为Router),Route,Link三个组件。新版本的react-router提出了一切都以Component实现的原则,因此这些组件实际上都是React.Component的实现。
BrowserRouter是一个容器Component(组件),其内部实现了路由跳转的逻辑。
Route也是一个Component(组件),配置了页面路径以及当用户输入的路径命中时需要渲染的组件。
Link用于跳转,有点像HTML的a标签。不一样的是Link是需要在后端进行编译,最终可能以a标签的形式呈现给用户。