由于在工作中,经常使用vue,对react并不是很熟练,本篇将通过对比vue的方式来学习react。
react特点
1、Fragment
非占位元素标签组件
import { Fragment } from 'react'
class TodoList extends Component{
render(){
return (
<Fragment>
<div>
<input />
<button>提交</button>
</div>
<ul>
<li>学英语</li>
<li>Learning React</li>
</ul>
</Fragment>
)
}
}
2、React中构造函数会最新被执行,可以在构造函数中定义状态state
constructor(props){
super(props)
this.state = {
inputValue: '',
list: []
}
}
3、绑定值跟vue相似,但语法稍有差别
<input value={this.state.inputValue}/>
4、实现双向数据绑定跟vue相似,vue中使用指令v-model
,v-model
在vue中是:value
和@input
事件的语法糖.
vue代码
<input type="text"
value="price"
@input="price=$event.target.value">
react代码
<input
value={this.state.inputValue}
onChange={this.handleInputChange.bind(this)}
/>
handleInputChange(e){
this.setState({
inputValue: e.target.value
})
}
不同之处在于,vue中监听的是input
事件,而react中监听的是onChange
事件,注意,react中事件名一定要写成onChange
, 不能写成原生的onchange
。另外在给input
绑定事件handleInputChange
的时候,一定要通过bind(this)
方式指定其执行的作用域。
5、react中的for
循环。
react中没有像vue中的指令v-for
, 只能通过编写常规的js代码实现循环的逻辑。
<ul>
{
this.state.list.map((item, index) => {
return <li key={index}>{item}</li>
})
}
</ul>
此处要注意的一点,就是我们使用了index
值作为key
值,这种方法是我们不推荐使用的,因为动态变化的index
做 key
值的时候,会影响到diff
算法的过程。具体你可以查看我之前写过的文章《虚拟DOM(Virtual DOM)中动态更新视图的diff算法》。
6、改变state中数据源中的数组数据
跟vue中给数据源中push
数据方式不同,react中并不能直接修改state
中的值(存在immutable
的原因,相关知识你可以查看https://www.jianshu.com/p/825b7b4c401d
)。所以,我们先将数据拷贝出来,然后通过this.setState
方法修改数据
<button onClick={this.handleBtnClick.bind(this)}>提交</button>
handleBtnClick(){
this.setState({
list: [...this.state.list, this.state.inputValue],
inputValue: ''
})
}
7、删除数据的操作
<ul>
{
this.state.list.map((item, index) => {
return <li key={index} onClick={this.handleDelete.bind(this, index)}>{item}</li>
})
}
</ul>
handleDelete(index){
const list = [...this.state.list]
list.splice(index, 1)
this.setState({
list
})
}
8、react中的注释
单行注释
{/*这是单行注释*/}
多行注释
{
// 这里写多行注释
}
9、jsx语法中的注意事项
(1)、定义样式的时候要用className
,而不是class
。
import './index.css'
<input
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange.bind(this)}/>
(2)、label
标签中的for
属性要用htmlFor
代替。
<div>
<label htmlFor="insertArea">输入内容</label>
<input
className="input"
id="insertArea"
...
/>
...
</div>
(3)、使用了dangerouslySetInnerHTML
进行模版编译输出。当然这是一个危险的操作,可能会存在XSS
风险。在vue中,我们是通过指令v-html
实现的。
<ul>
{
this.state.list.map((item, index) => {
return <li
key={index}
onClick={this.handleDelete.bind(this, index)}
dangerouslySetInnerHTML={{__html:item}}>
</li>
})
}
</ul>
10、react中父子组件的数据通信
在vue中,父子组件的通信是通过props和$emit
通信的。在react中,原理相似,但稍微有一点差别。react中,父组件通过props
向子组件传递state
和方法(用于操作父组件state
中的数据),子组件接收到这些方法后,通过调用这些方法,实现对父组件数据的改变。
父组件TodoList
import TodoItem from './TodoItem'
<ul>
{
this.state.list.map((item, index) => {
return <TodoItem
key={index}
content={item}
index={index}
deleteItem={this.handleDelete.bind(this)}/>
})
}
</ul>
子组件TodoItem
import React, { Component } from 'react'
class TodoItem extends Component{
render(){
return (<li onClick={this.handleClick.bind(this)}>
{this.props.content}
</li>)
}
handleClick(){
this.props.deleteItem(this.props.index)
}
}
export default TodoItem
此处要注意一点,父组件在将方法传递给子组件的时候,需要通过bind(this)
指定其作用域,否则会存在this
指针错误的情况。
11、react编码的优化方案
(1)、在构造器中统一处理函数的this
绑定问题。
constructor(props){
super(props)
...
this.handleInputChange = this.handleInputChange.bind(this)
this.handleBtnClick = this.handleBtnClick.bind(this)
this.handleDelete = this.handleDelete.bind(this)
}
<div>
<label htmlFor="insertArea">输入内容</label>
<input
...
value={this.state.inputValue}
onChange={this.handleInputChange}/>
<button onClick={this.handleBtnClick}>提交</button>
</div>
(2)、修正this.setState
方法的正确使用姿势
之前的使用方式
handleDelete(index){
const list = [...this.state.list]
list.splice(index, 1)
this.setState({
list
})
}
修正后的使用方式
handleDelete(index){
this.setState((prevState) => {
const list = [...prevState.list]
list.splice(index, 1)
return { list }
})
}
此处主要强调参数prevState
的使用。
(3)、业务组件和视图组件的解耦
解耦前
<ul>
{
this.state.list.map((item, index) => {
return <TodoItem
key={index}
content={item}
index={index}
deleteItem={this.handleDelete.bind(this)}/>
})
}
</ul>
解耦后
<ul>
{
this.getItem()
}
</ul>
getItem(){
return (
this.state.list.map((item, index) => {
return <TodoItem
key={index}
content={item}
index={index}
deleteItem={this.handleDelete}/>
})
)
}
网友评论