react实现汉堡_初尝React——实现简单功能的小Demo

本文记录了一位从Vue转向React的开发者初次尝试实现一个简单的React应用,包括汉堡菜单功能。通过介绍React的基本语法和组件化思想,解释了如何使用ReactDOM.render()进行渲染,JSX语法构建组件,以及在React中处理数据和事件。同时,文章讨论了React中state管理和数据单向流动的原则,以及如何处理this的指向问题。
摘要由CSDN通过智能技术生成

看React文档一天,大致掌握了些基础语法。迫不及待手撸了个Demo。类似于记事本的功能,可以新增、删除、标记项目。基础的一个数据通信更改。

一直技术栈用的是Vue,在写Demo的时候,用的逻辑也是Vue的思想,难免很多地方绕了弯路,只能说用粗暴的方式实现了功能,不然React怎么可能这么复杂呢。

引入文件

分别引入React文件。由于React无法直接被浏览器识别,所以需要引入Babel文件进行编译。

引入代码核心js

注意,需要使用Babel编译的文件,需要在加上type="text/babel"。

css样式与root容器

注释部分是最后编译完成后,所需要展示的HTML结构。

开始编写reactList.js

界面布局

如同Vue需要传入el或者mount一个容器一样,React中提供了一个ReactDOM对象,所有顶层API都能在该对象上调用

ReactDOM.rander:在提供的 container 里渲染一个 React 元素,并返回对该组件的引用

rander中有两个参数,一个是需要渲染的内容,一个是内容渲染之后存放的容器

值得注意的是,第一个参数就如同Vue中组件的一样,只能有一个根元素。之后所有的rander渲染的内容同理。

ReactDOM.render(

新增

  • xxxx

    已完成

    删除

,

document.getElementById('root')

)

在React中,对元素的渲染使用了JSX——是一个看起来很像 XML 的 JavaScript 语法扩展。

在Vue中,我们在template中绑定数据,使用的是{{}}, 若是要绑定事件是@xxx, 绑定变量则是:xxx

在JSX中,皆在大括号{}中填写表达式。

React.Component支持用ES6中的Class来定义组件。

我们可以定义一个名为Layout的组件来代替在rander中的HTML

class Layout extends React.Component {

render() {

return (

)

}

}

class InputBox extends React.Component {

render() {

return (

新增

)

}

}

class List extends React.Component {

render() {

return (

  • xxxx

    已完成

    删除

)

}

}

ReactDOM.render(

,

document.getElementById('root')

)

注意:

1、自定义的组件名与类名大小写需要一致,首字母大写;

2、每个Class中都有一个render返回处理完之后的JSX;

3、return 若是多行代码,需要用();

初始化数据

1、每个Class都有一个constructor构造函数,可以不显式写出来,默认就有,在实例创建的时候初始化数据,只会执行一次。

2、React中的数据都维护在state中,就如同Vue中的data(){}。

3、不同的是,state中的数据不可以直接更改,需要用stateSet方法。

4、stateSet中的数据是直接覆盖,而不是更新。对于复杂的数据结构,需要在外部处理之后再传入stateSet

5、Class中的this指向比较复杂,参考知识库中文章class中this的指向

数据与事件的绑定

与Vue的数据双向绑定不同,React的理念是单向数据流。

父组件通过props传递数据给子组件。

而子组件通过绑定在子组件上的回调函数,来通知父组件。类似于Vue的this.$emit,React中是直接调用父组件通过props传进来的回调函数

class Layout extends React.Component {

// 为了直观,将多余代码注释

...

render() {

return (

newEvent={this.state.newEvent}

addItem={this.addItem}

/>

deleteItem={this.deleteItem}

finishItem={this.finishItem}

/>

)

}

}

在Layout组件中,分别有两个子组件与。我们统一将数据都维护在组件中,当父组件中的数据更改之后,子组件中的数据相应发送改变。子组件进行操作之后,将操作的数据通过绑定的回调函数(例如finishItem、deleteItem、addItem)通知父组件处理数据。以此达到兄弟组件之间的交互。

class Layout extends React.Component {

constructor(props) {

super(props)

this.state = {

data: [

{

name: '学react',

finish: false

},

{

name: '学vue',

finish: false

},

{

name: '学javascript',

finish: true

}

],

newEvent: ''

};

this.addItem = this.addItem.bind(this)

this.deleteItem = this.deleteItem.bind(this)

this.finishItem = this.finishItem.bind(this)

}

// 为了直观,将多余代码注释

...

render() {

return (

newEvent={this.state.newEvent}

addItem={this.addItem}

/>

deleteItem={this.deleteItem}

finishItem={this.finishItem}

/>

)

}

}

在Dom元素上绑定事件的时候,需要绑定事件的执行上下文,或者使用箭头函数。目的就是防止this的隐式丢失。

还是以为例,在子组件上绑定的事件,我们都在构造函数中显式绑定了this的指向。

因为函数中this的指向,不取决于作用域,而是取决于执行上下文的this指向。因为点击事件是在Dom上调用的,所以点击时候,函数隐式被绑定window,但是React的类中采用的是严格模式,所以this指向的是undefined。

解决this的指向问题

解决this的指向问题,目前我所知的是四种形式。

1、在构造函数中显式绑定this

class Layout extends React.Component {

constructor(props) {

this.finishItem = this.finishItem.bind(this)

}

finishItem() {

console.log(this)

}

}

2、在Dom的点击事件上绑定this

render() {

return (

)

}

3、用箭头函数

因为箭头函数的this是在定义函数时绑定的,而不是在执行时候绑定。

render() {

return (

this.addItem}/>

)

}

4、使用React.createClass来定义类

React.createClass与React.Component来创建类,区别还是很大的。可以说React.createClass更加便利,React自身就已经实现了,包括this的绑定。

const Layout = React.createClass({

render() {

return (

this.addItem}/>

);

}

});

代码总览

Document

.input-wrap {

display: flex;

align-items: center;

}

.input-wrap button {

margin-left:10px;

}

li {

display: flex;

align-items: center;

margin-bottom: 10px;

}

li button {

margin-left: 10px;

}

li div {

width: 100px;

}

.finishItem {

text-decoration: line-through;

}

class Layout extends React.Component {

constructor(props) {

super(props)

this.state = {

data: [

{

name: '学react',

finish: false

},

{

name: '学vue',

finish: false

},

{

name: '学javascript',

finish: true

}

],

newEvent: ''

};

this.addItem = this.addItem.bind(this)

this.deleteItem = this.deleteItem.bind(this)

this.finishItem = this.finishItem.bind(this)

}

addItem(val) {

if (!val) {

alert('请填写项目名称!')

return

}

console.log(this.state.data)

// 直接覆盖 而不是更新

const newData = this.state.data.concat({ name: val, finish: false })

this.setState({

data: newData

})

}

finishItem(index) {

console.log(index)

const list = this.state.data

list[index].finish = !list[index].finish

this.setState({

data: list

})

}

deleteItem(index) {

console.log(index)

const list = this.state.data

list.splice(index, 1)

this.setState({

data: list

})

}

render() {

return (

)

}

}

class InputBox extends React.Component {

constructor(props) {

super(props)

this.state = {

newEvent: props.newEvent

}

this.handleChange = this.handleChange.bind(this)

}

handleChange(e) {

this.setState({

newEvent: e.target.value

})

}

render() {

return (

this.props.addItem(this.state.newEvent)}>新增

)

}

}

class List extends React.Component {

render() {

return (

{this.props.list.map((i, index) => {

return (

{i.name}

this.props.finishItem(index)}>{i.finish ? '撤销完成' : '已完成' }

this.props.deleteItem(index)}>删除

)

})}

)

}

}

ReactDOM.render(

,

document.getElementById('root')

)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值