“这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战”
我争取把每一步都可以写成可以实操的,希望跟着写写练练。
项目跑起来
首先安装脚手架并使用脚手架新建一个项目
#安装脚手架
npm i create-react-app -g
#创建项目
create-react-app react-demo
使用vscode打开项目,整个项目目录如下所示:
react-demo
├── README.md
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock
整个项目的入口是src/index.js,该文件实现的功能是:调用ReactDOM.render方法渲染视图。
先来看下 ReactDOM.render方法,函数签名如下:
ReactDOM.render(element,container[,callback])
该方法的作用就是将React元素(element)渲染到提供的container(dom元素)里面去,并返回对该组件的引用,可以点开官方文档看看API
接下来看下 React元素 是什么?
官网说,React元素其实是 JSX表达式的结果(表达式1+2的结果是3,结果可以理解为返回值)。
JSX是什么
JSX是JS的一种语法拓展,允许在JS中写类似于HTML的结构。举个例子:
const element = <h1>Hello, world!</h1>;
上面的element常量就是一个React元素
修改index.js文件的内容如下
const element=<h1>hello,world</h1>
ReactDOM.render(
element,
document.getElementById('root')
);
刷新页面,会发现浏览器的页面会渲染出element的内容。由此可知App和element是一类东西。这里App称为组件。
在学习组件之前,先熟悉下JSX的语法
JSX中允许出现表达式,表达式用{}括起来
const name="Jack"
const Welcom=<h1>Hi,{name}</h1>
//表达式可以是变量、函数调用、数字表达式(a+b)等
const getTime=()=>{}
const Clock=<h1><span>现在是:</span> <b>getTime()</b></h1>
//与Html的区别
//html中的class在JSX中是className
const blog=<section className="blog"></section>
//绑定style
const btnStyle={padding:'5px 20px'}
const myBtn=<button style={btnStyle}></button>
//或者直接写到一起
const myBtn1=<button style={{padding:'5px 20px'}}></button>
//绑定事件
const clickHandle=()=>{}
const myBtn2=<button onClick={(e)=>{clickHandle(e)}}></button>
说明了JSX语法的基础使用,下面看下React中的组件。
React中的组件
React中有两种组件,一种是函数式组件,类似于上面的App。一种是class组件。
在React Hooks出现之前,函数式组件是不能拥有自己内部的状态的,只能通过父组件传递props然后展示内容,这也是react推荐的一种编程方式。 修改App.js的代码如下,体验下函数式组件的写法:
// 函数式组件 父组件传递的props作为函数参数传入
function Logo({src}){//接收props
return <img src={src} className="App-logo" alt="logo" />
}
//调用Logo组件
function App() {
return (
<div className="App">
<header className="App-header">
<Logo src={logo}></Logo> //传递props
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
</header>
</div>
);
}
还有一种组件是class组件,使用的话需要先继承React.Component,class组件的学习可以和vue组件对应着来,vue可以实现的在react中都要能实现
假如我们要实现一个显示当前时间的组件,该组件显示的color由父组件控制
vue2实现如下:
<template>
<section :style="{ color: color }">当前时间:{{ curTime }}</section>
</template>
<script>
export default {
name: 'clock',
props: {
color: {
type: String,
default: '#333',
},
},
data() {
return {
curTime: 0,
timer: 0,
}
},
mounted() {
this.timer = setInterval(() => {
console.log('hahah')
this.curTime = new Date()
}, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
},
}
</script>
react实现如下: 可以把代码复制到App.js中跑一下,看下效果
//组件定义
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {//相当于vue中的data
curTime: 0,
timer: 0
}
}
componentDidMount() {//相当于vue声明周期的mounted
const timer = setInterval(() => {
this.setState({ curTime: new Date().toString() })
}, 1000)
this.setState({ timer: timer })
}
componentWillUnmount() {//相当于vue生命周期的beforeDestroy
clearInterval(this.state.timer)
}
render() {
return (
<section style={{ color: this.props.color }}>
当前时间:{this.state.curTime}
</section>
)
}
}
//组件调用
<Clock color="#fff"></Clock>
实例-列表查询组件 对比vue2和react组件的区别
下面来个复杂点的例子,在对比中熟悉一下react class component的使用
写一个列表查询的例子
整体业务流程是:
- QueryList组件获取数据,传递props给List,List遍历数据渲染视图
- Query查询时,把searchKey发送给QueryList,QueryList获取数据,根据searchKey筛选,传递props给List渲染视图
总共包含三个组件
- QueryList
- List
- Query
先实现List组件
vue实现
<template>
<section>
<section v-if="list.length == 0">暂无数据</section>
<div style="margin-top: 10px" v-for="item in list" :key="item.name">
ID:{{ item.id }} 姓名:{{ item.name }} 年龄:{{ item.age }}
</div>
</section>
</template>
<script>
export default {
name: 'List',
props: {
list: {
type: Array,
default: () => [],
},
},
computed: {
noData() {
return this.list.length == 0
},
},
}
</script>
<style lang="less" scoped></style>
使用react实现
import React from 'react'
class List extends React.Component{
constructor(props){
super(props)
console.log()
}
get noData(){//computed
return this.props.list.length===0
}
getList(){
return this.props.list.map(item=>{
return <div key={item.name}> ID:{ item.id } 姓名:{ item.name } 年龄:{ item.age }</div>
})
}
render(){
const list=this.getList()
const dom=this.noData?<div>暂无数据</div>:<div>{list}</div>
return <div>{dom} </div>
}
}
export default List
对比一下可以看出以下几点区别,
-
vue中的props需要先声明再使用,react中可以直接使用
-
vue列表渲染是使用v-for指令,react是使用JS数组的map方法返回JSX进行渲染
-
vue中有计算属性,react中没有,但是可以通过getter实现,如 get noData(){}
-
vue中有v-if,react中无,但是可以通过别的方式实现,例如三元表达式
const dom=this.noData?<div>暂无数据</div>:<div>{list}</div>又比如canRender && <MyComponent/>
实现Query组件: vue实现
<template>
<section>
<input
placeholder="输入id"
style="padding: 12px; font-size: 40px"
v-model="id"
@input="handleChange"
/>
</section>
</template>
<script>
export default {
name: 'Query',
data() {
return {
id: '',
}
},
methods: {
handleChange() {
//向父组件发送数据
this.$emit('on-change', this.id)
},
},
}
</script>
<style lang="less" scoped></style>
react 实现
import React from 'react'
class Query extends React.Component{
constructor(props){
super(props)
}
testThis(){
console.log(this)
}
onChange=(e)=>{//防止this丢失
// 向父组件发送消息
this.props.onQuery(e.target.value)
}
render(){
return <input style={{padding:'10px',fontSize:'20px'}} placeholder="输入id" onChange={this.onChange} />
}
}
export default Query
区别如下:
-
vue向父组件发送消息使用 this.$emit(),react是直接调用父组件的方法,即
this.props.callback -
vue中元素绑定事件使用@事件名, react中元素绑定事件使用on事件名,此外需要注意,react中元素绑定事件需要注意this丢失的问题,注意上面的onChange方法的定义
QueryList组件
vue实现
<template>
<section>
<!-- 查询列表组件 查询框 列表 -->
<query @on-change="handleChange"></query>
<list :list="list"></list>
</section>
</template>
<script>
import query from './query'
import list from './list'
import axios from 'axios'
export default {
name: 'query-list',
components: {
query,
list,
},
data() {
return {
list: [],
}
},
methods: {
async getList(id = -1) {
const res = await axios.request({
method: 'get',
url: '<http://111.229.14.189/gk-api/util/list>',
params: {
id: id,
},
})
this.list = res.data
},
handleChange(id) {
this.getList(id)
},
},
created() {
this.getList()
},
}
</script>
react实现
import React from 'react';
import Query from './Query.js'
import List from './List.js'
import axios from 'axios'
class QueryList extends React.Component{
constructor(props){
super(props)
this.state={
list:[]
}
}
componentDidMount(){
this.getList()
}
async getList(id=-1){
const res=await axios.request({
method:'get',
url:'<http://111.229.14.189/gk-api/util/list>',
params:{
id:id
}
})
this.setState({list:res.data})
}
handleQuery=(value)=>{
this.getList(value)
}
render(){
return (
<div className="query-list" >
<Query onQuery={this.handleQuery}></Query>
<List list={this.state.list}></List>
</div>
);
}
}
export default QueryList;
区别如下:
-
vue中在created或者mounted中调用接口,react在componentDidMount中调用接口
-
vue中组件自己的状态在data中定义,修改的直接this.list=xxx;react中组件自己的状态定义在this.state中,修改的话需要使用this.setState({list:xxx})
总体来说,写过vue的人来写react,会发现react class component写法略繁琐。不过好在react出了hooks语法,可以去除很多冗余,下篇文章介绍hooks。