脚手架创建项目
// 全局安装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 脚本(启动脚本,打包脚本..)
基本项目结构
- 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
}
如果要获取到最新状态值有以下三种方式
- 传递函数给setState方法
this.setState((state, props) => ({
counter: state.counter + 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>
)
}