React学习01

为什么要学习React?

起源于Fackbook内部项目,2013年5月开源

声明式编程 what vs how(命令式编程)

高效(通过虚拟DOM,最大程度减少与DOM的交互)

灵活(与已知的库或框架可以很好地配合)

JSX(JavaScript + XML)JavaScript语法的扩展

组件化(通过React构建组件,增加代码复用性)

单向数据流(顶层组件控制数据的变化,父组件流向子组件,降低副作用)

React内容:

React基础

React Hooks

React-router

Redux

组件库

Immutable

Mobx

React + TS

单元测试

dva + umi

虚拟DOM

传统DOM的更新:真实页面对应一个DOM树。传统开发模式中,每次更新页面时,都要手动操作DOM进行更新。100条DATA -> 99条DATA 【销毁100条再创建99条】

虚拟DOM思想:DOM的操作非常昂贵。在前端开发中,性能消耗最大的就是DOM操作,而且这部分代码会让整体项目的代码变得难以维护。React把真实DOM树转换为JavaScript对象树,即VirtualDOM。类似于{ type:'div', text: 'I am div' },数据变化会经过新旧VDOM对象经过diff算法进行对比后,以最小的更新代价,再进行一次真实DOM的更新。

create-react-app

1. 全局安装create-react-app

npm install -g create-react-app

2. 创建一个项目

create-react-app 项目名称

3. 如果不想全局安装,也可以使用临时安装npx

npx create-react-app 项目名称

这个过程需要一段时间,主要会安装这三个东西

  • react: react的顶级库
  • react-dom: 因为react有很多运行环境,如app端的react-native,web上就是react-dom
  • react-scripts: 包含运行和打包react应用程序的所有脚本和配置

JSX语法与组件

JSX语法:JSX将HTML语法直接加入到JavaScript代码中,再通过翻译器转换到纯JavaScript后再由浏览器执行。在实际开发中,JSX在产品打包阶段都已经编译成纯Javascript,不会带来任何副作用,反而会让代码变得更加直观并易于维护。编程过程由Babel的JSX编译器实现。

Class组件

ES6加入的让JavaScript直接支持使用class定义一个类,react创建组件的方式就是使用类的继承,ES6class是目前官方推荐的使用方式,它使用ES6标准语法来构建。

注意点:

1. 类名使用大驼峰

2. return 的内容换行就要加小括号()

3. JSX要有一个根节点,可以使用幽灵节点<></>

import React from "react"

class App extends React.Component {
  render() {
    return (
      <>
        <h2>App</h2>
      </>
    )
  }
}

export default App;

函数组件

function App () {
  return (
    <>
      <h2>App</h2>
    </>
  )
}

export default App

注意:函数式组件v16.8版本之前被认为是无状态组件

v16.8之后引入了React hooks,函数组件就有了状态

组件的嵌套

import React, { Component } from 'react'

class NavBar extends Component {
  render () {
    return <div>NavBar -- <NavBarChild></NavBarChild></div>
  }
}
function NavBarChild() {
  return <div>NavBarChild</div>
}

function Swiper () {
  return <div>Swiper</div>
}

const TabBar = () => {
  return <div>TabBar</div>
}
export default class App extends Component {
  render () {
    return (
      <div>
        <NavBar></NavBar>
        <Swiper></Swiper>
        <TabBar></TabBar>
      </div>
    )
  } 1
}

组件的样式

行内样式写法

import React, { Component } from 'react'

export default class App extends Component {
  render () {
    const textStyle = { color: 'green', fontSize: 24, backgroundColor: 'orange' }
    return (
      <>
        <div style={{ color: 'red', fontSize: 24 }}>I am Text1</div>
        <div style={textStyle}>I am Text2</div>
      </>
    )
  }
}

外部css导入写法

先定义外部index.css样式文件

.text {
  color: blue;
  font-size: 26px;
  font-weight: 600;
}

引入并使用

import React, { Component } from 'react'
import './index.css' // 引入样式文件
export default class App extends Component {
  render () {
    const textStyle = { color: 'green', fontSize: 24, backgroundColor: 'orange' }
    return (
      <>
        {/* style行内写法 */}
        <div style={{ color: 'red', fontSize: 24 }}>I am Text1</div>
        <div style={textStyle}>I am Text2</div>
        {/* className写法 */}
        <div className='text'>I am made by className</div>
        <label htmlFor="username">请输入用户名:</label>
        <input type="text" id='username' />
      </>
    )
  }
}

注意:

React推荐我们使用行内样式,因为React认为每一个组件都是一个独立的个体。

其实我们大多数情况下还是大量在为元素添加类名。但是需要注意的是在JSX中,class属性要写为className,for属性要写成htmlFor。(因为jsx/js中class和for为关键字)。

事件绑定

import React, { Component } from 'react'

export default class App extends Component {
  a = 666
  // 推荐函数写法(不存在this指向问题)
  handleAdd = () => {
    console.log('add')
  }

  handleChange = (e, param1, param2) => {
    console.log(e.target.value)
    console.log(`params: ${param1} ${param2}`)
  }
  handleSend (param1, param2, param3) {
    console.log(param1, param2, param3)
  }
  render () {
    return (
      <div>
        {/* 传递e和参数的写法 */}
        <input type="text" onChange={(e) => this.handleChange(e, 'a', 'b')} />
        <button onClick={this.handleAdd}>Add</button>
        {/* 传递参数写法 */}
        <button onClick={() => this.handleSend(1, 2, 3)}>send</button>
      </div>
    )
  }
}

React中的事件绑定:

React并不会真正地绑定事件到每一个具体元素上,而是采用事件代理的模式

React中的event对象:

和普通浏览器一样,事件handler会被自动传入一个event对象,这个对象和普通浏览器的event对象所包含的方法和属性都基本一致。不同的是React中的event对象不是浏览器提供的,而是·它自己内部构建的。它同样具有event.stopPropagation、event.preventDefault这种常用的方法。

ref的使用

1. 给标签或组件设置ref="myText",通过这个获取this.$refs.myText,ref可以拿到该真实DOM或组件对象.(该方法即将启用,在严格模式下会报错)

import React, { Component } from 'react'

export default class App extends Component {
  handleAdd = () => {
    console.log(this.refs.myText.value)
  }
  render() {
    return (
      <div>
        <input type="text" ref='myText'/>
        <button onClick={() => this.handleAdd()}>add</button>
      </div>
    )
  }
}

2. 另一种写法(推荐)

import React, { Component } from 'react'

export default class App extends Component {
  myText = React.createRef()
  handleAdd = () => {
    console.log(this.myText.current)
    console.log(this.myText.current.value)
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.myText}/>
        <button onClick={() => this.handleAdd()}>add</button>
      </div>
    )
  }
}

组件数据挂载方式

状态(state)是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护,使用状态的目的就是为了在不同状态下使用组件的显示不同(自己管理)。

state初体验demo

import React, { Component } from 'react'

export default class App extends Component {
  // 状态
  state = {
    isSave: 'false'
  }
  // button状态切换
  handleClick = () => {
    this.setState({
      isSave: !this.state.isSave
    })
  }
  // render
  render () {
    return (
      <div>
        <button onClick={this.handleClick}>{this.state.isSave ? '保存' : '取消'}</button>
      </div>
    )
  }
}

注意:this.state是纯js对象,在Vue中,data属性是利用了Object.defineProperty或Proxy处理过的,更改data数据的时候会触发数据的getter和setter,但是React中没有做这样的处理,如果直接更改的话,react是无法得知的,所以需要使用特殊的更改状态的方法setState。

补充另一种写法:也可以把state写在类组件的构造器constructor中

import React, { Component } from 'react'

export default class App extends Component {
  // constructor
  constructor() {
    super()
    // 状态
    this.state = {
      isSave: 'false'
    }
  }
  // button状态切换
  handleClick = () => {
    this.setState({
      isSave: !this.state.isSave
    })
  }
  // render
  render () {
    return (
      <div>
        <button onClick={this.handleClick}>{this.state.isSave ? '保存' : '取消'}</button>
      </div>
    )
  }
}

列表渲染

import React, { Component } from 'react'

export default class App extends Component {
  state = {
    // 列表数据
    cityList: [
      { id: 1, name: 'ShangHai' },
      { id: 2, name: 'BeiJing' },
      { id: 3, name: 'London' },
    ]
  }

  render () {
    return (
      <div>
        <ul>
          {this.state.cityList.map(item => <li key={item.id}>{item.name}</li>)}
        </ul>
      </div>
    )
  }
}

注意:key的问题

<li>1</li><li>2</li><li>3</li>    ->>>     <li>1</li><li>3</li>

key值起到标识作用,使新的VDOM尽可能的复用旧的VDOM

TodoList小案例

import React, { Component } from 'react'
import { v4 as uuid } from 'uuid'
export default class App extends Component {
  state = {
    inputValue: '',
    showList: [
      { id: 1, text: 'aaa' },
      { id: 2, text: 'bbb' },
      { id: 3, text: 'ccc' },
    ]
  }
  handleInputChange = (e) => {
    this.setState({
      inputValue: e.target.value
    })
  }
  handleAdd = () => {
    this.setState({
      showList: [...this.state.showList, { id: uuid(), text: this.state.inputValue }],
      inputValue: ''
    })
  }
  handleDelete = (curItem) => {
    this.setState({
      showList: this.state.showList.filter(item => item.id !== curItem.id)
    })
  }
  render () {
    return (
      <div>
        <label htmlFor="addInput">请输入:</label><input type="text" id='addInput' value={this.state.inputValue} onChange={(e) => this.handleInputChange(e)} />
        <button onClick={this.handleAdd}>添加</button>
        <ul>
          {this.state.showList.map((item, index) => <li key={item.id}>
            {/* dangerouslySetInnerHTML富文本编辑器=>解析出代码片段*/}
            <span dangerouslySetInnerHTML={{
              __html: item.text
            }}></span>
            <button onClick={() => this.handleDelete(item)}>删除</button></li>)}
        </ul>
        {/* 条件渲染 */}
        {this.state.showList.length === 0 ? <h2>暂无待办事项</h2> : null}
        {this.state.showList.length === 0 && <h2>暂无待办事项哦~</h2>}
      </div>
    )
  }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值