React:框架的核心包
ReactDOM:渲染相关的包
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(
// 严格模式节点
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)
严格模式节点,会影响useEffect的执行时机
<React.StrictMode>
</React.StrictMode>
JSX
JavaScript xml 能在js中书写html结构。用声明式书写html结构,底层调用命令式createElement。
let getName = () =>{return '小红'}
function App () {
return(
<div>{getName()}
</div>
)
}
react中使用数组map方法重复渲染模板,类似vue中v-for
let list = [a,b,c]
function App () {
return(
<div>
{list.map((i) =>{
<span>{i}</span>
})}
</div>
)}
react中使用if else或者三元表达式或者逻辑运算符选择渲染模板,类似vue中v-if
let falg = true
let getHalg = () => {
if(falg){return <span>哈哈哈</span>
}else {
return null
}
}
function App () {
return(
<div>
{falg ? <span>哈哈哈</span> : null}
{falg && <span>哈哈哈</span>}
{getHalg()}
</div>
)}
jsx 样式控制
import './app/css'
let style = {
color:'red',
fontSize:'20px'
}
function App () {
return(
<div>
// 行内样式
<span style={{color:'red',fontSize:'20px'}}>hahaha</span>
// 抽离行内样式
<span style={style}>hahaha</span>
// 引入css文件直接写类名
<span className='active'>hahaha</span>
// 动态控制样式 用三元或者if else 或者逻辑运算符
<span className={ture ? 'active' : ''}>hahaha</span>
</div>
)}
jsx必须有一个根节点,没有根节点可以用<></>代替根节点
jsx属性名采用驼峰命名
jsx支持多行,如果需要换行,需要使用()包裹,防止bug出现。
组件
函数组件,类式组件必须继承React.Component,必须调用render()函数
事件绑定,不传参数默认传递事件对象e,传参数,第一位固定是事件对象e。
事件绑定onClick={clickHandler}和onClick={clickHandler()}不同,
前者表示给onClick绑定clickHandler函数,
后者表示把clickHandler()函数执行结果给onClick,
所以传参数是要使用高阶函数,onClick={() => {clickHandler()}}
import React from "react"
class HelloComponent extends React.Component{
// 类组件事件绑定
clickHandler = (e) => {}
render(){
return <div onClick={this.clickHandler}>类式组件</div>
}
}
function About() {
// 函数组件事件绑定
let clickHandler = (e) => {}
return (<div onClick={clickHandler}>函数式组件</div>)
}
function About() {
return (<div>
<About />
<HelloComponent />
</div>)
}
类式组件状态“不可变”,不要直接修改状态中的值,而是基于状态中的值创建新的状态值,进行赋值。this问题,类式组件中如果事件不写成变量赋值+箭头函数形式,this指向会有问题,
可以在constructor中用bind改变指向方式解决this问题,也可以在绑定事件时用高阶函数解决this问题。
import React from "react"
class HelloComponent extends React.Component{
// 类式组件状态
constructor(){
// 构造函数this指向实例对象方式
this.state = {a:1}
this.clickHandler = this.clickHandler.bind(this) // 修正写法
}
// 变量声明实例对象方式
state = {
a:1,
list:[1,2],
person:{
b:1}
}
// 类组件事件绑定
clickHandler(){} // 有问题写法
clickHandler = (e) => {
// 修改状态中的数据,必须调用setState()方法
this.setState({
a:4,
list:[...this.state.list,3,4],
person:{
...this.state.person,
c:1}
})}
render(){
// 第一种写法
return <div onClick={this.clickHandler}>类式组件{this.state.a}</div>
// 第二种写法 原理箭头函数父级为render函数,render函数this指向为组件实例对象
return <div onClick={() => this.clickHandler()}>类式组件{this.state.a}</div>
}
}
受控组件 类似vue中v-model
import React from "react"
class HelloComponent extends React.Component{
state = {
a:1
}
clickHandler = (e) => {
this.setState({
a:e.target.value
})}
render(){
return <input type='text' value={this.state.a} onChange={this.clickHandler}></input>
}
}
非受控组件
createRef函数
import React,{createRef} from "react"
class HelloComponent extends React.Component{
ref = createRef()
clickHandler = (e) => {
this.ref.current.value
}
render(){
return <>
<input type='text' ref={this.ref}></input>
<button onClick={this.clickHandler}></button>
</>
}
}
组件间通信
props是只读对象,可以传递的数据类型,数字,字符串,布尔值,数组,对象,函数,jsx
props校验使用第三方包。
函数组件两种写法,使用defaultProps或者使用es6形参定义默认值。
类式组件两种写法使用defaultProps或者使用static关键字定义静态方法。
通过props传递jsx 类似vue中插槽。
通过props传递函数可以做到子向父传递数据。
import React from "react"
// 引入校验规则包
import PropTypes from 'prop-types'
// 子组件
function Son(props){return (<div>我是函数子组件{props.mess}</div>)}
// 定义校验规则
Son.propTypes = {}
// 默认校验规则也可以用es6给函数形参定义默认值
Son.defaultProps= {}
// 子组件
class Sons extends React.Component{render(){return (<div>我是类式子组件{this.props.mess}</div>)}}
// 父组件
class App extends React.Component{
state = {mess:'haha'}
render(){return (<div>
<son msg={this.state.mess}></son>
<sons msg={<span></span>}></sons>
</div>)}}
Provider和Consumer
import React,{createContext} from "react"
let context = createContext()
// 根组件
function App(){
return (
<Provider value={this.state.mess}>
<div><c /></div>
</Provider>
)
}
// 子组件
function C(){
return (
<Consumer>
{value => <span>{value}</span>}
</Consumer>
)
}
children属性
children属性可以写 普通文本,普通标签元素,函数,jsx
目的主要用高阶组件,用函数包裹一个组件,可以用作鉴权组件,类似vue-router中路由导航守卫。
import React from "react"
// 根组件
function AuthComponent(props){
let children = props.children
// 判断token是否存在
if(token){
// 渲染子组件C
return (<>{children}</>)
}else{
// 编程式导航去往登录页
return <Navigate to="/login" replace />
}
}
// 子组件
function C(){
return (
<div></div>
)
}
// 使用方式<AuthComponent><C /></AuthComponent>
生命周期
只有类式组件才有生命周期
挂载:constructor(执行constructor中的代码,初始化只执行一次) render(每次组件渲染都会触发) componentDidMount(组件挂载后执行,初始化的时候执行一次)
更新:render(每次组件渲染都会触发) componentDidUdate(可以获取到更新后的dom内容)
卸载:componentWillUnmount(执行清理作用)
Hooks
useState可以调用多次,每一次都是独立的。
useState只能出现在函数组件中,不能嵌套在if或者for或者其他函数中。
useEffect副作用函数,修改状态,更新组件时,副作用函数也会执行,也可以根据依赖指定执行时间,是在dom更新之后。
import {useState, useEffect} from "react"
function App(){
useEffect(() => {
// 清理副作用函数,类似组件销毁生命周期
return () => {}
// 发送ajax请求,修改dom,本地存储。
// 第二个参数是依赖项,useEffect回调函数中用到的数据就应该添加进依赖项数组中,不然容易出bug。
// 不添加数组,初始化执行,修改状态,更新组件时,执行。
// 添加空数组,初始化执行
// 添加具体依赖数组,初始化执行,依赖数组中依赖项变化时执行。
},[count])
//发送网络请求,包成一个函数,否则清理函数无法立即返回。
useEffect(
()=> {
async function getData(){
let res await axios.get('/api')
}
},
[])
// 解构赋值,名字可以自定义,顺序不能调换,一个useState中setCount方法只能修改一个count,不能交叉修改,如setH不能修改count,只能修改h。
let [count, setCount] = useState(0)
let [h, setH] = useState(0)
// useState第二种写法
let [b, setB] = useState(() => {
return getHander()
})
return (
<div>
<button onClick={() => setCount(count + 1)} />
</div>
)
}
useRef,
import {useRef,createContext,useState,useContext} from "react"
let Context = createContext()
let [count,setCount] = useState(0)
function App(){
let aRef = useRef(null)
return(<Context.Provider>
<div>
<A ref={aRef} />
</div>
</Context.Provider value={count}>)
}
function A(){
let count = useContext(Context)
return(<div></div>)}
react-router
import Home from "./Home"
import About from "./About"
import Board from "./Board"
import {BrowserRouter,Link,Routes,Route,Outlet} from "react-router-dom"
function App(){
return(
//声明当前路由模式,history模式是BrowserRouter。HashRouter是hash模式
<BrowserRouter>
// 指定跳转的组件,to用来配置路由地址,类似vue-router中router-link。
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
//路由出口,类似vue-router中 router-view
<Routes>
//指定路径和组件的对应关系,path代表路径,element代表组件。类似vue-router中路由配置表
<Route path='/' element={<Home />}>
// 嵌套二级路由
<Route path='/board' element={<Board />}></Route>
// 默认二级路由
<Route index element={<Board />}></Route>
</Route>
<Route path='/about' element={<About />}></Route>
// 配置404路由
<Route path='*' element={<Error />}></Route>
</Routes>
</BrowserRouter>)}
function Layout() {
// 二级路由出口
return (<idv><Outlet /></div>)
}
编程式路由导航
import {useNavigate} from "react-router-dom"
function Login(){
let navigate = useNavigate()
let goAbout = () => {navigate('/about')}
return (
<div>
<button onClick={goAbout}>
</button>
</div>
)
}
路由传参
import {useSearchParams,useParams} from "react-router-dom"
function Login(){
let [params] = useSearchParams()
let params = useParams()
// pamas参数要在路径上占位
<Route path='/about/:id' element={<About />}></Route>
// params是一个对象,对象上有get方法,把参数的名称作为get方法的实参传过来,类似vue-router中的路径占位符。
let id = params.get('id')
return (
<div>
<button onClick={goAbout}>
</button>
</div>
)
}
mobx
import {makeAutoObservable} from 'mobx'
class CounterStore {
// 定义数据
count = 0
list = [1,2,3,4,5,6]
constructor(){
// 数据响应式
makeAutoObservable(this)
}
// 修改数据
add = () => {
this.count++
}
// 定义计算属性
get filterList(){
return this.list.filter(item => item > 2)
}
}
// 实例化,暴露实例对象。
let counterStore = new CounterStore()
export{counterStore}
// 导入mobx数据
import counterStore from './store/counter'
// 导入react和mobx中间件
import {observer} from 'mobx-react-lite'
function App(){
return (
<div>
{counterStore.count}
</div>
)
}
// 中间件包裹App组件,使数据变成响应式。
export default observer(App)
模块化
import {ListStore} from './list.Store'
import {CounterStore} from './counter.Store'
import React from 'react'
class RootStore {
constructor(){
this.ListStore = new ListStore()
this.CounterStor e= new CounterStore()
}
}
// 实例化
let rootStore = new RootStore()
// 函数式组上createContext方法,不穿参数,通过Provider标签上value属性查找值,没有value值,查找传入的参数。
let context = React.createContext(rootStore)
// 函数式组上useContext方法,获取value值,没有value值,获取传入的参数。
let useStore = () => React.useContext(context)
// useStore函数返回值就是rootStore实例对象
export {useStore }