阅读 6159

vue转react(第一天 看看React的组件 )

这是我参与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方法渲染视图。

image.png 先来看下 ReactDOM.render方法,函数签名如下:

ReactDOM.render(element,container[,callback])
复制代码

该方法的作用就是将React元素(element)渲染到提供的container(dom元素)里面去,并返回对该组件的引用,可以点开官方文档看看API

官方文档render()

接下来看下 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的使用

写一个列表查询的例子

image.png

整体业务流程是:

  1. QueryList组件获取数据,传递props给List,List遍历数据渲染视图
  2. 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。

代码地址

文章分类
前端
文章标签