安装:
概述
- React起源于FaceBook的内部项目,因为该公司对市场上所有的JavaScript MVC框架都不满意,就决定自己写一套用来假设Instagram的网站,2013年5月开源。
- 一般有三个库文件,react.js,react-dom.js和Browser.js,它们必须首先加载,其中react.js是React的核心库,react-dom.js是提供与DOM相关的功能,Browser.js的作用是将JSX的语法转换为JavaScript语法,这一步很消耗时间,最好放到服务器完成。
- script标签的type属性:
- 自己书写的js代码,script标签的type属性要改成:text/babel,这是因为React独有的JSX语法跟javaScript不兼容。凡是使用JSX的地方都要加上type="text/balbel"
- $babel src --out build :将src子目录的js文件进行语法转换,转码后的文件全部放在build子目录
核心:
ReactDoM.render()
- 是React的最基本的用法,用于将模板转为HTML语言,并插入指定的DOM节点。
JSX语法:
- 概述:JavaScript的扩展语法。JSX用来声明React当中的元素。
- 基本解析规则:遇到HTML标签(以<开头),就用HTML规则解析,遇到代码块(以{开头的),就用javascript规则解析。
- 书写规则:一般都会带上换行和缩进,增强代码可读性。同时在JSX代码纹面扩上一个小括号,这样可以防止分号自动插入的bug,
- eg1:
var names = ['alice', 'emily', 'kate'];
ReactDOM.render(
<div>
{
names.map(function (name){
return <div key={v.toString()}>Hello,{name}!</div>
})
}
</div>, // 注意使用循环结构时要添加key
document.getElementById('example')
);
//运行结果:
- eg2:
const element = <h1>Hellow, world!</h1>
- 可以用引号来定义以字符串为值的属性:
const element = <div tabIndex = "0></div>;
- 使用大括号来定义以javascript表达式为值得属性:
const element = <img src = {user.avatarUrl}/>
- 注意
- 如果使用了大括号包裹javascrit表达式,就不要在外面用引号了。JSX会将引号当中的内容识别为字符串而不是表达式
- 因为JSX的特性更接近Javascript所以使用驼峰命名来定义属性名。
- 想要给渲染出的html标签添加一个类名要写成:className = "类名",不能用class
- JSX防注入攻击:
- 可以放心的在JSX中使用用户输入,ReactDom在渲染之前会默认过滤所用传入的值。他可以确保你的应用不会被注入攻击。所有内容在渲染之前都被转换成了字符串。
- JSX转化:
- Babel转义器会把jsx转换成一个名为React.createElement()的方法调用。
元素渲染:
- 元素是构成React应用的最小单位。与浏览器的Dom元素不同,React当中的元素事实上是普通的对象,ReactDOM可以确保浏览器DOM的数据与React元素保持一致。
- 将元素渲染到DOM中。
- 通过ReactDOM.render()的方法来将其渲染到页面上:
- 该方法有两个参数:第一个是要渲染的React元素,第二个是要插入的DOM节点。
- React的元素都是不可变的,元素被创建之后,你是无法改变其内容或者属性的,一个元素好像就是动画里的一帧,它代表应用界面在某一时间点的样子。对于初学者来说,更新界面的唯一办法是创建一个新的元素,然后将它传入React.render()方法。
- eg
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
如下方法通过setInterval计时器每秒钟调用一个ReactDOM.render()
注意: 在实际生产开发中大多数应用只会调用一个ReactDOM.render()
-
React只会更新必要的部分。
- ReactDOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新变化的部分。如上的例子中React只改变了页面中数字发生变化的部分。
组件&&props
概述:
- 组件可以将UI切成一些独立的、可服用的部件,这样你就只需要专注构建每一个单独的部件。从概念上看其就像是函数,他可以接收任意值(称之为“props”),并返回一个需要在页面上展示的React元素。
组件的定义:
- 定义一个组件最简单的方式是使用Javascript函数(必须要有一个return值):
- eg:
规则:
- 无论是使用函数或是类来声明的组件都不能修改他自己的props(列入:给props增加属性,删除属性,更改属性值)。
function Welcome() {
return <h1>Hello,{props.name}</h1>
}
// 该函数是一个有效的React组件,他接收一个单一的'props'对象并返回一个React元素。我们之所以成这种类型的组件为函数定义组件,是因为从字面上来看,他就是一个javascript函数。
- 我们也可以使用ES6的class来定义一个组件:
- eg
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
组件渲染
- react的元素可以是HTML元素,也可以是用户的自定义的组件
const element = <welcome name = "Sara" />
- 当React遇到的元素是用户自定组件,他会将JSX属性作为单个的对象传递给改组件,这个对象称之为'props'
- eg:
function Welcome (props){
retrun <h1>Hello,{props.name</h1>
}
const element = <Welcome name = "Sara" />
ReactDOM.render(
element,
document.getElementById('root')
);
// 如上在页面展示内容为:Hello ,Sara
- 渲染流程:
1.我们对<Welcome name="Sara"/>元素调用了ReactDOM.render()方法。
- React将{name: 'Sara'}作为props传入并调用Welcome组件。
- Welcome组件将<h1>Hello, Sara</h1>元素作为结果返回。
- ReactDOM将DOM更新为<h1>Hello,Sara</h1>
- 注意:组件的名称必须以大写字母开头。eg:<div/>表示一个DOM标签,但<Welcome/>表示一个组件并限定了它的可用范围
- 组合组件:
- 组件可以在他的输出中引用其他组件:
组件的生命周期和状态
应用条件
- 组件的状态state:与属性非常相似,但是是私有的,完全受控于当前组件。
- 要想使用组件的生命周期钩子函数,或者使用给组件加状态必须以类的形式定义组件。
概述:
- 每个组件都有几个生命周期函数,以will为前缀的函数是发生在母线是之前条用,以did为前缀的是在发生某些事之后调用。
Mounting : 如下方法在组件实例被创建和被插入到dom中时被调用。
- constructor():
- 在组件被mounted之前调用,我们的组件继承自React.Component,constrcutor函数中我们在其他操作前应该先调用super(props),否则this.props将会是undefined.
- constructor是初始化state的好地方。如果我们不需要初始化state,也不需要bind任何方法,那么我们的组建中不需要出现constructor函数。
- 注意如下情况,很容易产生bug,我们通常的做法是,提升state到父组件中,而不是使劲儿的同步state和props.
constructor (props){
super(props);
this.state={
color:props.initialColor
};
}
-
componentWillMount()
- 此方法在mounting之前被立即调用,他在render()之前调用,因此在此方法中setState不会触发重新渲染。此方法是服务渲染中调用的唯一的生命周期钩子,通常我们建议使用constructor()
-
render()
- render()方法应该是一个纯方法,级他不会修改组价的state,在每一次调用时返回同样的结果。他不直接和浏览器交互,如果我们 想要交互,应该在compentDidMount()或者其他的生命中期函数里面。
-
componentDidMount()
- 此方法在组件被mounted之后立即被调用,初始化dom接单应该在此方法中,如果要从远程获取数据,这里是实例化网络请求的好地方。此方法中setState会触发组件重新渲染。
-
Updating
- props和state的改变产生更新。在重新渲染组件时,如下的方法被调用:
- componentWillReactProps(): 一个已经mounted的组件接受一个新的props之前,componentWillReceiveProps()被调用,如果我们需要更新state来相应prop的更改,我们可以再此方法中比较props和nexProps并使用this.setState来更改state.
- 注意: 即使props没有改变,React也可以调用这个方法,因此如果你只想要处理改变,请确保比较当前值和下一个值。当父组件重新渲染时,可能会发生这种情况。
- React在组件mounting期间不会调用此方法,只有在一些组件的props可能被更新的时候才会调用。调用this.setState通常不会触发发componentWillReceiveProps。
-
shouldComponentUpdate()
- 使用此方法让React知道组件的输出是否不受当前state或props更改的影响。默认行为实在每次state更改是重新渲染组件,在大多数情况下,我们应该默认该行为。 当接收到新的props或state时,shouldComponentUpdate()在渲染之前被调用。默认返回true,对于初始渲染或者使用forceUpdate()时,不调用此方法。返回false不会阻止子组件的state更改时,该子组件的重新渲染。
-
componentWillUpdate()
- 当接收新的props或state时,componentWillUpdate()在组件渲染之前被立即调用。使用此函数作为更新方程之前执行准备的机会。初始渲染不会不调用此方法。
- 注意:这里不能调用this.setState(),如果调用了会产生死循环,一只更新。
组件的生命周期和状态简述:(总共10个api)
实例化
- getDefaultProps
作用于组件类,只调用一次,返回对象用于设置的默认props,对于引用值,会在实例中共享。 - getInitialState
作用于组件的实例,在实例创建时调用一次,用于初始化每个state,此时可以访问this.props。 - componentWillMount
在首次完成渲染之前条用,此时仍可以修改组件的state. - render
比选方法,创建虚拟DOM,该方法具有特殊的规则:- 只能通过this.props和this.state访问数据。
- 可以返回null,false或者任何React组件(返回React组件时,必须要有一个根元素)。
- 只能出现一个顶级组件(不能返回数组)
- 不能改变组件的状态。
- 不能改DOM的输出。
- componentDidMount
正式DOM被渲染出来之后调用,在方法中可以通过this.getDOMNode()访问到真实的DOM元素。此时可以使用其他累出来操作这个DOM。在服务端中,改方法不会被调用。
存在期
- componentWillReceiveProps
组件接收到props时调用,并将其作为参数nextProps使用,此时可以更改组件的props及state.
componentWillReceiveProps:function(nextProps){
if(nextProps.bool){
this.setState({
bool: true
});
}
}
- shouldComponentUpdate
组件是否应当渲染新的Props或者state,返回false表示跳过后续生命周期方法,通常不需要使用以避免出现bug。在出现瓶颈时,可以通过该方法进行适当的优化。 - componentDidUpdate
完成渲染新的props或者state后调用,此时可以访问到新的DOM元素。 - componentWillUnmount
组件被移除之前被调用,可以用于做一些清理工作,在componentDidMount方法中添加的所有任务都需要在该方法中撤销,比如创建的定时器或添加的事件监听器。
state与props的区别:
state的作用:
- state是React中组件的一个对象。React把用胡界面当做是状态机,想象他又不同的状态,然后渲染这些状态,可以轻松的让用户界面与数据保持一致。
- react中,更新组建的state最导致重新渲染用户界面(不要操作DOM),简言之:就是用户界面会随着state变化而变化。
state工作原理:
- 常用的通知React数据变化的方法是调用setState(data,callback).这个方法。这个方法会合并data到this.state,并重新渲染组件。渲染完成后,调用可选的callback,大部分情况不需要提供callback,因为React会负责吧界面更新到最新状态。
应用场景:
- 大部分组件的工作原理应该是从props里取数据并渲染出来。但是,有时需要对用户的输入,服务器请求或者时间变化做出响应,这是才需要state.
- 组件应该尽可能的无状态,这样能隔离state.把他放到最合理的地方(Redus做的就是这个事情),也能减少冗余并易于解释程序运作过程。
- 常用的模式就是创建多个只负责渲染数据的无状态(stateless)组件,在他们的上层创建一个有状态(statefull)组件并把它的状态通过props传递给子级,有状态的组件封装了所有的用户交互逻辑,而这些无状态组件只负责声明是的渲染数据。
那些应该作为state
- state应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。中数据一般很小且能被JSON序列化
条件渲染:
- React中的条件渲染和javascript中的一致,使用javascript操作符if或者条件运算符来创建当前的元素,然后让React根据他们来更新UI。
function UseGreeting(props){
return <h1>Welcome back!</h1>
}
function GuestGreeting(props){
return <h1>Please sign up.</h1>
}
// 创建一个条件渲染组件。
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
- 元素变量:可以使用变量来存储元素。他可以帮助你有条件的渲染组件的一部分,儿输出的其他部分不会改变。
//新建两个无状态组件
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
/// 创建一个有状态组件。
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
- 与运算符 &&
可以通过用花括号包裹代码在JSX中嵌入任何表达式,也包括javascript的逻辑&&,他可以方便的条件渲染一个元素。
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
- 三目运算符:条件渲染的另一种方法是使用javascript的条件运算符:condition?true:false
eg1:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
eg2:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
- 阻止组件渲染:在极少数的情况下,你可能希望隐藏组件,即使他被其他组件渲染。让render方法返回null而不是他的渲染结果即可实现。
function (!props.warn){
return null
}
return (
<div className = "warning">
Warning!
</div>
)
}
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 (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
列表&keys
- 渲染多个组件:
可以通过使用{}在JSX内构件一个元素集合
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
// 把整个listItems插入到ul元素中,然后渲染DOM:
ReactDOM.render(
<ul>{listItems}</ul>
document.getElementById('root')
);
- 基础列表组件:
通常你需要渲染一个列表到组件中
function NumberList(props){
const number = props.number;
const listItems = number.map((number)=>{
<li>{number}</li>
});
return (
<ul>{listItems}</ul>
)
}
const numbers = [1,2,3,4,5];
ReactDOM.render(
<NumberList number = {numbers} />
document.getElementById('root')
) ;
- keys
keys可以在DOM中的木屑元素被增减或者删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素富裕一个明确的标识。一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的id作为元素的key,当元素没有确定的ID时,你可以使用他的序列号索引index作为key