React学习

102 阅读3分钟

脚手架创建项目

// 全局安装create-react-app脚手架
npm i create-react-app -g
// 创建项目
npx create-react-app react-demo
// 启动项目
npm start
// 暴露配置项 默认配置项是隐藏的
npm run eject
// 执行之后会根目录下生成config和scripts两个文件夹
// config webpack配置相关
// scripts 脚本(启动脚本,打包脚本..)

基本项目结构

image.png

  • config webpack配置相关
  • public 静态资源、模板文件
  • scripts 脚本文件
  • src 源码
    • App.js 根组件
    • index.css 主样式
    • index.js 入口文件
    • reportWebVitals.js 监听CLS、FID、FCP、LCP、TTFB数据
  • .env 环境配置
  • package.json 依赖

注意:目前默认使用React18的版本, 执行render渲染跟之前有些区别

// src/index.js 入口文件
// react18版本
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
)

// react17以及之前版本
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDom.render(<App />, document.getElementById('root'))

<React.StrictMode> 开启严格模式
StrictMode 是一个用以标记出应用中潜在问题的工具。就像 Fragment ,StrictMode 不会渲染任何真实的UI。它为其后代元素触发额外的检查和警告
注意: 严格模式检查只在开发模式下运行, 不会与生产模式冲突。** 使用strictMode有以下几个优点:

  • 识别不安全的生命周期组件
  • 废弃方法警告
  • 检测意外的副作用
  • 检测过时的context API

基础语法

组件

组件是独立的抽象模块。react中有两种形式: function组件和class组件

  • class组件
    class组件通常拥有状态和生命周期,继承于Component,实现render方法
// src/pages/Home.js
import { Component } from "react";

export default class Home extends Component {
  constructor(props){
    super(props)
    this.state = {
      flag: true
    }
  }
  render() {
    const name = 'react study'
    const user = {
      firstName: 'tom',
      lastName: 'jerry'
    }
    const formatName = function(user) {
      return user.firstName + ' ' + user.lastName
    }
    const arr = [1,2,3,4,5]
    let { flag } = this.state
    const clickHandle = () => { // 使用箭头函数 保证this指向
      console.log('click....');
      this.setState({
        flag: !this.state.flag
      })
    }

    return (
      <>
        <h1>这是Home页面</h1>
        <p>数据绑定:{name}</p>
        <p>方法调用:{formatName(user)}</p>
        <p>数组使用(模拟vue中v-for):</p>
        <ul>
          {
            arr.map((item, index) => {
              return <li key={'item' + index}>{item}</li>
            })
          }
        </ul>
        <div>
          <button onClick={clickHandle}>切换隐藏内容</button>
        </div>
        <p>模拟vue中的v-if: {flag && <span>显示内容</span>}</p>
      </>
    )
  }
}
  • function组件
    函数通常是无状态的,仅关注内容展示,引入hooks之后,函数组件也能够拥有状态
import React, {useState, useEffect } from 'react'
export default function Clock() {
  // 定义变量和对应的set方法 useState中设置初始值
  const [date, setDate] = useState(new Date())
  // Similar to componentDidMount and componentDidUpdate:
  useEffect (() => {
    const timerId = setInterval(() => {
      setDate(new Date())
    }, 1000)
    return () => {
      clearInterval(timerId)
    }
  })
  return (
    <>
      <h1>这是函数组件</h1>
      <div>{date.toLocaleTimeString()}</div>
    </>
  )
}

事件回调函数中this指向,三种常见处理方式

  • 构造函数中绑定并覆盖
class Home extends Component {
    constructor(props) {
        super(props)
        this.clickHandle = this.clickHandle.bind(this)
    }
    clickHandle() {
        console.log('click event....')
    }
    return (
        <button onClick={this.clickHandle}>按钮</button>
    )
}
  • 方法定义为箭头函数
class Home extends Component {
    clickHandle = () => {
        //使⽤用箭头函数,不不需要指定回调函数this,且便便于传递参数
        console.log('click event....')
    }
    return (
        <button onClick={this.clickHandle}>按钮</button>
    )
}
  • 事件调用时,改为箭头函数
class Home extends Component {
    clickHandle(){
        //使⽤用箭头函数,不不需要指定回调函数this,且便便于传递参数
        console.log('click event....')
    }
    return (
        <button onClick={() => this.clickHandle}>按钮</button>
    )
}

setState特性理解

  • 用setState修改状态不能通过属性方式修改
this.state.counter += 1 // 错误的
this.setState({
    counter: this.state.counter + 1
})
  • setState是批量执行,对同一个状态的多次操作只会执行一次
constructor(props) {
    super(props)
    this.state = {
        counter: 0
    }
}
componentDidMount() {
    this.setState({counter: this.state.counter += 1})
    this.setState({counter: this.state.counter += 2})
    this.setState({counter: this.state.counter += 3}) // 只会执行最后一次
    console.log('counter:', this.state.counter) // 0
}
render() {
    let { counter } = this.state
    return <div> {counter} </div> // 显示3
}
  • setState通常是异步的
constructor(props) {
    super(props)
    this.state = {
        counter: 0
    }
}
componentDidMount() {
    this.setState({counter: this.state.counter += 1})
    console.log('counter:', this.state.counter) // 0
}
render() {
    let { counter } = this.state
    return <div> {counter} </div> // 显示1
}

如果要获取到最新状态值有以下三种方式

  1. 传递函数给setState方法
this.setState((state, props) => ({
    counter: state.counter + 1
}))
  1. 使用定时器
setTimeout(() => {
  this.setState({
    counter: this.state.counter + 1
  })
}, 0)

组件通信

父子间组件通过props属性传递

// app.js
function App() {
  const getMsgFromChild = function(msg) {
    console.log('msg from child: ', msg)
  }
  return (
    <div className="App">
      <Home msg='msg from parent' getMsg={getMsgFromChild} />
    </div>
  );
}
// home.js
function home(props) {
    return (
    <div>{props.msg}</div>
    <button onClick={() => props.getMsg('msg to parent')}>向父组件传递参数</button>
   )
}

生命周期

生命周期图谱 image.png