React简介
React在2013年5月开源。
React可能是将来web开发的主流工具。
React不是一个完整的MVC框架,顶多充当一个View层。
-
MVC(Model+View+Controller)
不适用于前端开发,因为View不允许知道用户的输入,用户的输入是从Controller这一层进入。然而用户直接通过view层交互,所以不可能不监听View层。
MVVM(Model+View+ViewModel)
——MVC的演变,更适合前端的开发模式。
-
JSX 解析器
将JSX转化成JS,在JS中直接编写HTML。
通过组建的state
来维护改变HTML DOM中的内容。
所有和Dom有关的都应该通过框架来维护,
将各功能做成组建——模板(容器)、控件。
-
React组件及数据传递
React是一个组件化的框架,在项目开发之初需要将组件分化
搭建React Start Kit
1. 新建项目文件夹
这里取名newReactproject。
在该目录下打开终端,初始化package.json
npm init
(可以输入项目的名称,这里为new-react-project
)
2. 安装插件
npm install --dev-save browser-sync gulp gulp-webpack jsx-loader react react-dom
3. JSX转换成JS的方法
在gulpfile.js中用webpack来将.jsx文件转化为.js文件
(gulp的使用在其他的章节里面会详细说明)
var webpackConfig = {
output:{
filename: 'index.js'
},
devtool: 'inline-source-map',
module:{
loaders:[
{test: /\.jsx$/, loader: 'jsx-loader'}
]
},
resolve:{
extensions:['','.js','.jsx']
}
}
gulp.task('script',function(){
gulp.src('./jsx/index.jsx') //以index.jsx为程序的入口
.pipe(webpack(webpackConfig))
.pipe(gulp.dest('./www/script/'))
.pipe(browserSync.stream());//同步浏览器
})
如此一来,就可以在.jsx文件中撰写开发代码了。
同时,需要注意的是:index.jsx中需要引用react
var React = require('react');
var ReactDom = require('react-dom')
如果需要在index.jsx中引用的组件,例如header,footer等,需要使用module.exports
module.exports = React.createClass({
render:function(){
return <p>这是一个React页面</p>
}
})
注意:实际项目中,node_modules文件会被删除 ,那么运行项目的时候需要在终端输入以下命令:
npm install gulp-cli -g
npm install
gulp
4. render语法
render一个变量时,要用html的方法来写。
例如:
ReactDom.render(<Main />,document.getElementById('main'));
前面一个指render的内容,后一个变量是render的目的地
注意:ReactDom.render
是新版本的写法,旧版本是React.render()
//jsx语法中类名:
className="className";
//jsx语法中样式:
style={{background:'#f00'}}
//jsx语法:
<tag prop={a:value}>{children}</tag>
//转换成js是:
React.createElement(tag, {a:value}, children)
创建一个组件类,需要注意的几点:
- React中创建的组件类以大写字母开头,
驼峰命名法
- 在React中使用React.createClass方法创建一个组件类
- 核心代码:每个组件类都必须实现自己的
render
方法。输出定义好的组件模板。返回值:null、false、组件模板 - 注意:组件类只能包含一个顶层标签
5. React Component
- render:渲染html的方法
- getInitialState: 返回初始化的State的方法
- getDefaultProps:返回默认props的方法
(state维护component内部的状态变化,props是component的外部的参数传入component的方式)- propTypes:定义props的类型的属性
- mixins:用来合并两个组件的属性
- statics:定义静态对象的属性
- displayName:定义该类在Debug信息中显示的名称
6. Props
Props是组件自身的属性,一般用于嵌套的内外层组件中,负责传递信息(通常是由父层组件向子组件传递)
注意:props对象中的属性与组件的属性一一对应,不要直接去修改props中的属性值。
//定义WebName
var WebName = React.createClass({
render:function(){
return <h1>{this.props.webname}</h1>;
}
})
//定义WebLink
var WebLink = React.createClass({
render:function(){
return <a href={this.props.weblink}>{this.props.weblink}</a>;
}
})
//定义WebShow
var WebShow = React.createClass({
render:function(){
return (
<div>
<WebName webname={this.props.wname} />
<WebLink weblink={this.props.wlink} />
</div>
);
}
})
//渲染
ReactDOM.render(
<WebShow wname="网站名称" wlink="http://www.baidu.com" />,
document.getElementById("container")
)
-
...this.props:
Props
提供的语法糖,可以将父组件中的全部属性都复制给子组件
例如:定义一个组件Link,Link组件中只包含一个<a>
,我们不给<a>
设置任何属性,所有属性全部从父组件肤质得到。代码如下:
var Link = React.createClass({
render:function(){
return <a {...this.props}>{this.props.name}</a>
}
});
ReactDOM.render(
<Link href="http://www.baidu.com" name="百度"/>,
document.getElementById("container")
)
//这样父组件上的属性href和name都会被复制到子组件Link中的<a>上。
-
this.props.children:
children是一个例外,不是跟组件的属性对应的。children表示组建的所有子节点
var ListComponent = React.createClass({
render:function(){
return (
<ul>
{
/*
列表项数量以及内容不确定,在创建模板时才能确定
利用this.props.children从父组件获取需要展示的列表项内容
获取到列表项内容后,需要遍历children逐行进行设置
使用React.Children.map方法
该方法的返回值:数组对象
*/
React.Children.map(this.props.children, function(child){
//child是便利得到的父组件的子节点
return <li>{child}</li>
})
}
</ul>
)
}
});
//渲染
ReactDOM.render(
(
<ListComponent>
<h1>百度</h1>
<a href="http://www.baidu.com">http://www.baidu.com</a>
</ListComponent>
),
);
7. 属性验证 propTypes
组件类的属性,用于验证组建实例的属性是否符合要求
var ShowTitle = React.createClass({
propTypes: {
//title数据类型必须为字符串
title:React.PropTypes.string.isRequired
},
render:function(){
return <h1>{this.props.title}</h1>
}
});
ReactDOM.render(
<ShowTitle title="123" />,
document.getElementById("container")
)
-
设置组件属性的默认值
通过实现组件的getDefaultProps方法,对属性设置默认值。
var MyTitle = React.createClass({
getDefaultProps: function(){
return {
title: "百度"
};
},
render: function(){
return <h1>{this.props.title}</h1>
}
});
ReactDOM.render(
<MyTitle />,
document.getElementById("container")
);
8. state:
state和props一样都是组件自身的属性,都可以用来传递数据。
在和用户交互的过程中,组件的状态可能需要更新,就会触发组件的重新渲染。
先举个例子说明React事件的引用:
//定义一个button组件,绑定onClick事件
//React中的事件名称首字母小写,驼峰命名法
var MyButton = React.createClass({
handleClick: function(){
alert('点击按钮触发的效果');
},
render: function(){
return (
<button onClick={this.handleClick}>{this.props.buttonTitle}</button>
)
}
});
ReactDOM.render(
<MyButton buttonTitle="按钮" />,
document.getElementById("container")
);
在知道事件引用的方法后,再举个经典案例:
需求:创建一个CheckButton的组件,包含一个checkbox类型的input,复选框在选中和未选中的两种状态下回显示不同的文字,即根据状态渲染。
var CheckButton = React.createClass({
//定义初始状态
getInitialState: function(){
return {
//在这个对象中设置的属性将会存储在state中
//默认状态是:未选中
isCheck: false
}
},
//定义事件绑定的方法
handleChange: function(){
//修改状态值,通过this.state读取设置的状态值
this.setState({
isCheck: !this.state.isCheck
});
},
render:function(){
//根据状态值,设置显示的文字
//在JSX语法中,不能直接使用if..else函数,使用三目运算符
var text = this.state.isCheck ? "已选中" : "未选中";
return (
<div>
<input type="checkbox" onChange={this.handleChange} />
{text}
</div>
);
},
});
//渲染
ReactDOM.render(
<CheckButton />,
document.getElementById("container")
);
需要注意的时:当state发生变化时,会调用组件内部的render方法
-
表单
举例说明:
需求:定义一个组件,将用户在输入框内输入的内容进行实时显示
分析:组件与用户交互过程中,存在状态的变化,即输入框的值。
var Input = React.createClass({
getInitialState: function(){
return (
value: "请输入"
);
},
handleChange: function(event){
//通过event.target.value读取用户输入的值
this.setState({
value: event.target.value
});
},
render: function(){
var value = this.target.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
)
},
});
ReactDOM.render(
<input />,
document.getElementById("container")
);
9. React Component生命周期时间
组件的生命周期分为三个状态
:
-
Mounting
: 组件挂载,已插入真实DOM相关接口:
(1)
componentWillMount
- 组件将要挂载。
在render之前执行,但仅执行一次,即使多次重复渲染该组件,或者改变了组件的state(2)
componentDidMount
- 组件已经挂载。
在render之后执行,同一个组件重复渲染只执行一次 -
Updating
: 组件更新,正在被重新渲染相关接口:
(1)
componentWillReceiveProps
(object nextProps)- 已加载组件收到新的props之前调用,注意组件初始化渲染时则不会执行(2)
shouldComponentUpdate
(object nextProps, object nextState) - 组件判断是否重新渲染时调用。该接口实际是在组件收到了新的props或者新的state的时候会立即调用,然后通过下面两个方法来进行更新(3)
componentWillUpdate
(object nextProps, object nextState) - 组件将要更新(4)
componentDidUpdate
(object prevProps, object prevState) - 组件已经更新 -
Unmounting
: 组件移出,已移出真实DOM相关接口:
componentWillUnmount
- 在组件要被移除之前的时间点触发,可以利用该方法来执行一些必要的清理组件的工作
生命周期中与props和state相关的接口:
(1)getDefaultProps
- 设置props属性默认值
(2)getInitialState
- 设置state属性初始值
总结下来,一共九个接口,如下:
- componentWillMount:组件的html即将加载时调用
- componentDidMount:组件的html已经加载时调用
- componentWillReceiveProps:组件props改变时调用
- shouldComponentUpdate:判定组件是否更新HTML
- componentWillUpdate:组件即将更新HTML时调用
- componentDidUpdate:组件HTML更新完后调用
- componentWillUnmount:组件HTML即将卸载时调用
- getDefaultProps:设置props属性默认值
- getInitialState:设置state属性初始值
组件的生命周期可分为四个阶段
:创建
、实例化
、更新
、销毁
生命周期个阶段介绍
var Demo = React.createClass({
/*
一、创建阶段
流程:只调用getDefaultProps方法
*/
getDefaultProps: function(){
//在创建类的时候被调用,设置this.props的默认值
console.log("getDefaultProps");
return {};
},
/*
二、实例化阶段
流程:
getInitialState,
componentWillMount,
render,
componentDidMount
*/
getInitialState: function(){
//设置this.state的默认值
console.log("getInitialState");
return {};
},
componentWillMount: functon(){
//在render之前调用
console.log("componentWillMount");
},
render:function(){
//渲染并返回一个虚拟DOM
console.log("render");
return <div>Hello React</div>
},
componentDidMount: function(){
//在render之后调用
//在该方法中,React会使用render方法返回的虚拟DOM对象创建真实的DOM结构
//可以在这个方法中读取DOM节点
console.log("componentDidMount");
},
/*
三、更新阶段
流程:
componentWillReceiveProps,
shouldComponentUpdate (如果返回值是false,后三个方法不执行),
componentWillUpdate,
render,
componentDidUpdate
*/
componentWillReciveProps: function(){
console.log("componentWillReciveProps")
},
shouldComponentUpdate: function(){
//是否需要更新
console.log("shouldComponentUpdate");
return true;
},
componentWillUpdae: function(){
console.log("componentWillUpdae");
},
componentDidUpdate: functon(){
console.log("componentDidUpdate")
},
/*
四、销毁阶段
流程:componentWillUnmount
*/
componentWillUnmount: function(){
console.log("componentWillUnmount")
},
});
//第一次创建并加载组件
//将得到以下顺序:getDefaultProps,getInitialState,componentWillMount,render,componentDidMount
ReactDOM.render(
<Demo />,
document.getElementById("container")
);
//第二次创建并加载组件
//将在第一次加载的基础上,添加以下顺序:componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render,componentDidUpdate
ReactDOM.render(
<Demo />,
document.getElementById("container")
);
//移除组件
ReactDOM.unmountComponentAtNode(document.getElementById("container"))
10. 设置组件的样式
- 内连样式
- 对象样式
- 选择器样式
注意:在React
和HTML5
中,样式的书写方式是有所区别的
主要体现在:
- HTML5以;结尾,React以,结尾
- HTML5中key、value都不加引号,React中属于JavaScript对象,key的名字不能出现“-”,需要使用驼峰命名法。如果value为字符串,需要加引号。
- HTML5中,value如果是数字,需要带单位,React中不需要带单位。
//样式
<style>
.pStyle {
font-size:20px;
}
</style>
//创建设置h1样式对象
var hStyle = {
backgroundColor:"green",
color:"red"
}
var ShowMessage = React.createClass({
render:function(){
return(
//内连样式
<div style={{backgroundColor:"yellow",borderWidth:5,borderColor:"black",borderStyle:"solid"}}>
//对象样式
<h1 style={hStyle}>{this.props.firstRow}</h1>
//选择器样式
<p className="pStyle">{this.props.secondRow}</p>
</div>
)
}
})
//渲染效果
ReactDOM.render(
<ShowMessage firstRow="第一行" secondRow="第二行"/>,
document.getElementById("container")
)
注意:在React中使用选择器样式设置组件样式时,属性名不能使用class
,因为class
是React
中的保留字,需要使用className
替换。
类似的还有使用htmlfor
替换for
,因为for
也是React
中的保留字。
11. 复合组件 —— 也称为组合组件,父子组件(创建多个组件合成一个组件)
//定义WebName组件
var WebName = React.createClass({
render:function(){
return <h1>网站名称</h1>;
}
});
//定义WebLink组件
var WebLink = React.createClass({
render:function(){
return <a href="http://www.baidu.com">http://www.baidu.com</a>;
}
});
//定义WebShow复合组件
var WebShow = React.createClass({
render:function(){
return (
<div>
<WebName />
<WebLink />
</div>
);
}
});
//渲染
ReactDOM.render(
<WebShow />,
document.getElementById("container")
);
注:以上所有内容都是本人的学习笔记和总结,仅供学习和参考,如果有遗漏或者不当的地方请谅解,请勿转载。