React
是跟 Vue 很相似的一套框架,它是Facebook
写的
框架特点:
- 声明式
- 组件化
安装
react.js - React 的核心库
react-dom.js - 提供与 DOM 相关的功能
babel.js
可以将 ES6 代码转为 ES5 代码,这样我们就能在目前不支持 ES6 浏览器上执行 React 代码。
Babel 内嵌了对 JSX 的支持。通过将 Babel 和 babel-sublime 包(package)一同使用
可以让源码的语法渲染上升到一个全新的水平
引入文件,必须先引react.js
再引react-dom.js
<script src="../js/react.js"></script>
<!-- 提供全局的 React变量 -->
<script src="../js/react-dom.js"></script>
<!-- 提供全局的 ReactDOM变量 webpack -->
<script src="../js/babel.js"></script>
使用
<script type="text/babel"><script>
中使用JSX(JS+HTML)语法
基本使用
react.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body>
<!-- View -->
<div id="demo"></div>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.js"></script>
<!-- JSX语法 script标签里面写的都是JSX语法,所以要设置type="text/babel"通知babel.js帮你把JSX转为JS -->
<script type="text/babel">
// react-dom提供的ReactDOM的render方法来渲染DOM结构
// render: ƒ (element, container, callback)
// element:HTML结构模板 container:选择器,会把结构渲染到选择器选中的结构中
// Model
// React是单向数据绑定的
// 视图变数据不变,这是react和vue的最大区别之一
// vue借助v-model,@xxx,v-on:xxx,才可以完成视图更改,数据变化
// react是没有任何指令的,所以要V->M是没有v-model,只有事件这种方法
ReactDOM.render(
<div>
<p>katsuki</p>
</div>,
document.querySelector("#demo")
)
</script>
</body>
</html>
声明式语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body>
<div id="demo"></div>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.js"></script>
<!-- react: View = Render(Model) -->
<script type="text/babel">
let data = {
name:"katsuki",
obj:{
age:18
},
arr:[
<li key='1'>ka</li>,
<li key='2'>tsu</li>,
<li key='3'>ki</li>
],
num: 16,
bool:true,
html: `
<p style="color:red">kasami</p>
`
}
let methods = {
renderString(){
return "katsuki desu"
}
}
/*
style接受的是对象,相当于`v-bind:style`或者`:style`
<p style={{
color: "pink",
fontSize: "18px"
}}></p>
*/
// <p name={data.name}></p> 相当于vue里面的v-bind:xxx
// {data.arr}会把数组遍历渲染出来
/*
<div dangerouslySetInnerHTML={{__html:data.html}}></div>
插入HTML结构可能夹带恶意代码导致程序崩溃
有被攻击的风险,故取名dangerouslySetInnerHTML
只变动data.html部分,其他是规定写法
*/
// 最后两个标签为函数使用
ReactDOM.render(
<div>
<p style={{
color: "pink",
fontSize: "18px"
}}>{data.name}</p>
<p name={data.name}>{data.obj.age}</p>
<p>数组</p>
<ul>{data.arr}</ul>
<p>{data.num+1}</p>
<p>{data.bool?'真':'假'}</p>
<div dangerouslySetInnerHTML={{__html:data.html}}></div>
<p>{methods.renderString()}</p>
<p>{
(function() {
return "muda muda"
})()
}</p>
</div>,
document.querySelector("#demo")
)
</script>
</body>
</html>
外层结构同上述例子,下面例子只写<script type="text/babel"></script>
中的内容和一些样式内容
用声明式来替代指令
大括号就叫声明式渲染,vue中的{{}}只能放变量,react中的{}可以放函数,由于react不像vue有指令,所以会在声明式中写函数来替代指令,甚至编写自己想要的功能。
模拟v-text&v-html
let data = {
name:"katsuki",
html:`
<p style="color:red">kasami</p>
`
}
let methods = {
vText(params){
return params
},
vHtml(html){
return <div dangerouslySetInnerHTML={{__html:html}}></div>
}
}
ReactDOM.render(
<div>
<p>v-text</p>
<p>
{
methods.vText(data.name)
}
</p>
<p>v-html</p>
<p>
{
methods.vHtml(data.html)
}
</p>
</div>,
document.querySelector("#demo")
)
模拟v-for
let data = {
name:"katsuki",
arr:[
<li key="1">ka</li>,
<li key="2">tsu</li>,
<li key="3">ki</li>
],
// 只要把arr2构造成arr的数组格式,就可以在声明式渲染里面显示该列表
arr2:['ka','tsu','ki']
}
let methods = {
vFor(arr){
return arr.map((item,index)=>{
return <li key={index} name={"li-"+item}>{item}</li>
})
}
}
ReactDOM.render(
<div>
<p>v-for</p>
<ul>
{
data.arr
}
</ul>
<ul>
{
methods.vFor(data.arr2)
}
</ul>
</div>,
document.querySelector("#demo")
)
模拟v-bind
let data = {
name:"katsuki",
size:50,
styleObj:{
color:'blue',
fontSize:`48px`
}
}
let methods = {
styleObj(){
return {
color:'yellow',
fontSize:`32px`
}
}
}
ReactDOM.render(
<div>
<p>v-bind</p>
<p data-name={data.name}>{`类名:`+data.name}</p>
<p>v-bind:style</p>
<p style={{
color:'pink',
fontSize:`${data.size}px`
}}>katsuki</p>
<p>v-bind:style</p>
<p style={
data.styleObj
}>kasami</p>
<p>v-bind:style</p>
<p style={
methods.styleObj()
}>Grisaia</p>
</div>,
document.querySelector("#demo")
)
模拟v-bind:class&v-show
<style>
.pink{
color:pink;
}
.red{
color:red;
}
.size{
font-size: 14px;
}
</style>
<script type="text/babel">
let data = {
bool:true
}
/*
在jsx中写class for属性值是关键字,直接写会冲突
需要分别改成className htmlFor
*/
ReactDOM.render(
<div>
<p>v-bind:class</p>
{/*<label htmlFor></label>*/}
<p className={
data.bool?'pink':'red'
}>katsuki</p>
<p>v-show</p>
<p style={{
display:data.bool?'block':'none'
}}>kasami</p>
</div>,
document.querySelector("#demo")
)
</script>
模拟v-if
let data = {
bool: true
}
let methods = {
vIf(bool){
if(bool,html){
return html;
}
}
}
ReactDOM.render(
<div>
<p>v-if</p>
{
(function(bool) {
if(bool){
return <p>katsuki</p>
}
})(data.bool)
}
<p>v-if</p>
{
methods.vIf(!data.bool,<p>kasami</p>)
}
</div>,
document.querySelector("#demo")
)
模拟v-on
监听事件,原生的写法onclick
而react需要on之后的那个字母大写onClick
原生 | React | Vue |
---|---|---|
onclick | onClick | @click/v-on:click |
onchange | onChange | |
onkeyup | onKeyup | |
… |
let data = {
name: 'katsuki',
age: 18
}
let methods = {
boChi(age,name,e){
console.log(age,name,e.target)
}
}
// 注释
ReactDOM.render(
<div>
<p>v-on</p>
<button onClick={
()=>{
console.log('katsuki desu')
}
}>OK</button>
{/*
methods.boChi 不传参执行
methods.boChi()会不等待点击直接执行,不符合原本意图
methods.boChi.bind(this) 这里的this指向当前节点button
*/}
<button onClick={
methods.boChi.bind(this,data.age,data.name)
}>OK</button>
</div>,
document.querySelector("#demo")
)
组件
函数式组件
纯展示组件,这种组件只负责根据外部传入的props来展示,书写简洁,执行效率更高
- 特点
1. 无state状态,只能访问传入的props属性
2. 组件不会被实例化,整体渲染性能得到提升
3. 组件不能访问this对象
4. 组件无法访问生命周期的方法
<style>
*{
margin: 0;
padding: 0
}
header{
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
background: gray;
color: pink;
}
</style>
<script type="text/babel">
// 正常方式
let Xkatsuki = (props) =>{
// 父组件传入值存入props
console.log(props)
return <header>{props.title}</header>
}
// 解构方式
let Xkatsuki = ({title}) =>{
return <header>{title}</header>
}
ReactDOM.render(
<div>
<Xkatsuki title="ka"/>
<Xkatsuki title="tsu"/>
<Xkatsuki title="ki"/>
{
((title) => {
return <header>{title}</header>
})("底部组件")
}
</div>,
document.querySelector("#demo"),
()=>{
console.log('katsuki desu')
}
)
</script>
类组件
类继承组件有丰富的特性(state状态、生命周期等)
<style>
*{
margin: 0;
padding: 0
}
header{
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
background: gray;
color: pink;
}
</style>
<script type="text/babel">
// 类组件
// 所有自定义组件都继承于React.Component,因为要继承一些React组件的基本方法
// 定义组件不要 div,header,p,组件首字母必须要大写
// 构造函数规范首字母大写
// 类组件 = 构造组件 = 构造函数声明的组件
class Xkatsuki extends React.Component{
constructor(props){
// 在类继承的构造函数中,要使用this,必须先执行super()
// 执行super()后才有this对象
super();// React.Component.call(this)
console.log(props)
this.props = props
}
render(){
return (
<header>{this.props.title}</header>
)
}
}
console.log(Xkatsuki)
let data = {
title1: "ka"
}
ReactDOM.render(
<div>
{/*props就是可以让组件呈现不同状态,而它的本质就是父组件(容器)把值传给子组件*/}
<Xkatsuki title={data.title1} age="18" skill="[js,html,css]" />
<Xkatsuki title="tsu" />
<Xkatsuki title="ki" />
{
((title) => {
return <header>{title}</header>
})("底部组件")
}
</div>,
document.querySelector("#demo"),
()=>{
console.log('katsuki desu')
}
)
</script>
state
state=>状态(数据模型),状态(数据)决定视图
// State -> View React
// data(model) <-> View Vue
class Xkatsuki extends React.Component{
constructor(props){
super(props)
console.log(props)
//父传过来的数据
this.props = props
//组件自身数据
//Model
this.state = {
name: "katsuki"
}
}
render(){
return (
<div>
<p style={{
color:'pink'
}}>props 父给的</p>
<p>{this.props.title}</p>
<p style={{
color:'pink'
}
}>state 自身给的</p>
<p>{this.state.name}</p>
</div>
)
}
}
ReactDOM.render(
<div>
<Xkatsuki title="ka" age="18" />
<Xkatsuki title="tsu" />
<Xkatsuki title="ki" />
</div>,
document.querySelector("#demo")
)
setState
> v-model(vue) = onChange + setState(react)
react的语法是{},单向数据绑定
vue的语法是{{}},双向数据绑定
vue中
1. data变了,view层通过v-xxx或者{{}}指令,来渲染数据 M->V
2. view变了,你通过v-on或者v-model来把数据从视图层带回数据层 V->M
react中
1. data变了,是通过函数式编程和{},来渲染数据 S->V
2. view变了,通过事件触发setState来更改数据层 V->S
// State -> View React
// data(model) <-> View Vue
class Xheader extends React.Component{
constructor(props){
super(props)
//父传过来的数据
this.props = props
//组件自身数据
//Model
this.state = {
name: "katsuki"
}
}
setValue(e){
console.log(this)
// e.target.value帮助完成把V的数据带回给M层
// V->M
// 配合事件和setState
this.setState({
name:e.target.value
})
}
render(){
return (
<div>
{/*onChange={this.setValue.bind(this)} bind中this指向Xheader*/}
<input onChange={this.setValue.bind(this)} value={this.state.name} />
<p style={{
color:'pink'
}
}>state 自身给的</p>
<p>{this.state.name}</p>
</div>
)
}
}
ReactDOM.render(
<div>
<Xheader title="kasami" age="18" />
</div>,
document.querySelector("#demo")
)
组件引入
项目结构
components
Xkatsuki.jsx
js
index.html
index.html body部分
<body>
<div id="demo"></div>
<script src="./js/react.js"></script>
<script src="./js/react-dom.js"></script>
<script src="./js/babel.js"></script>
<script type="text/babel" src="./components/Xkatsuki.jsx"></script>
<script type="text/babel">
ReactDOM.render(
<div>
<Xkatsuki />
</div>,
document.querySelector("#demo")
)
</script>
</body>
Xkatsuki.jsx
class Xheader extends React.Component{
constructor(props){
super(props)
this.props = props
}
render(){
return (
<header>katsuki</header>
)
}
}
本地打开会有下图错误
file协议
引入jsx的script标签
会跨域,需要在服务器环境下运行,比如搭建一个express脚手架
,把文件放到public文件夹
中,npm start
运行服务,详情参考博文Node_express
。
生命周期
生命周期 | Vue | React | 描述 |
---|---|---|---|
编译前 | beforeCreate | - | 数据和虚拟DOM和真实DOM都没有 |
编译后 | created | constructor | 有数据 |
挂载前 | beforeMount | componentWillMount | 有数据,有虚拟DOM,但没挂载 |
挂载后 | mounted | componentDidMount | 有数据,有虚拟DOM,有挂载 |
更新前 | beforeUpdate | componentWillUpdate | 更新数据,并且更新了虚拟DOM,但没挂载 |
更新后 | updated | componentDidUpdate | 真实DOM更新了 |
销毁前 | beforeDestory | - | 虚拟DOM销毁了,但真实DOM没销毁 |
销毁后 | destoryed | componentWillUnmount | 真实DOM销毁了 |
- | shouldComponentUpdate | 组件只要更新,就会触发这个生命周期,return 布尔值,为真DOM更新,否则不更新 |
componentWillReceiveProps
:这是接收新的props
时候调用的生命周期
componentWillReceiveProps(nextProps) {
const { getPropsData } = nextProps;
console.log(getPropsData);
}
shouldComponentUpdate
使用案例
<body>
<div id="demo"></div>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.js"></script>
<script type="text/babel">
class Xheader extends React.Component{
constructor(props){
super(props)
this.props = props
this.state = {
name: "katsuki"
}
}
setValue(e){
this.setState({
name:e.target.value
})
}
shouldComponentUpdate(){
// 如果返回true,页面更新,否则不更新
// 输入框输入内容长度大于7时,DOM不更新
if(this.state.name.length>7){
return false
}else{
return true
}
}
render(){
return (
<div>
<input onChange={this.setValue.bind(this)} value={this.state.name} />
<p style={{
color:'pink'
}
}>state 自身给的</p>
<p>{this.state.name}</p>
</div>
)
}
}
ReactDOM.render(
<div>
<Xheader title="katsuki" />
</div>,
document.querySelector("#demo")
)
</script>
</body>