一、State
步骤
- 导入useState
import React, {useState} from "react"
- 声明State
let [value, setValue] = useState(0)
数组第一个参数为使用的值,第二个参数为设置值的函数。useState的参数为默认值。
- 使用值
<div>
<span>{value}</span>
</div>
- 设置值、
setValue(value + 1)
参数即为对值得变更操作
代码示例
import React, { useState } from "react";
function App() {
let [value, setValue] = useState(0);
const add1 = () => {
setValue(value + 1);
};
return (
<div>
<span>{value}</span>
<button onClick={add1}>+1</button>
</div>
);
}
export default App;
二、useReducer
步骤
- 导入useReducer
import { useReducer } from "react"
- 创建初始值
const initial = {
n: 0
}
- 创建所有操作类型
const reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.number }
} else if (action.type === 'multi') {
return { n: state.n - action.number }
} else {
throw new Error("未知类型")
}
}
- 使用useReducer,获得读写操作
const [state, dispatch] = useReducer(action, initial)
读
<div>{state.n}</div>
写
dispath(type: "add", numer: 1 )
代码示例
import React from "react"
import { useReducer } from "react"
const initial = {
n: 0
}
const reducer = (state, action) => {
if (action.type === 'add') {
return { n: state.n + action.number }
} else if (action.type = "multi") {
return { n: state.n - action.number }
} else {
throw new Error("未知类型")
}
}
const DemoUseReducer = () => {
const [state, dispatch] = useReducer(reducer, initial)
const add = () => {
dispatch({ type: "add", number: 1 })
}
return (
<>
<div>{state.n}</div>
<button onClick={add}>+1</button>
<button onClick={() => dispatch({ type: "multi", number: 3 })}>-3</button>
</>
)
}
export default DemoUseReducer
三、useContext
步骤
- 导入createContext、useContext
import React, { useState, createContext, useContext } from "react"
- 创建Context
const Context = createContext(null)
- 设置作用域,传递你需要使用的数据
return (
<Context.Provider value={{n, setN}}>
<Father/>
<Son/>
</Context.Provider>
)
- 在作用域中的组件解构传递的数据
Father
const {n, setN} = useContext(Context)
- 使用解构出来的数据
Father
<button onClick={()=>setN(n=>n+1)}>+1</button>
代码示例
import React, { useState, createContext, useContext } from "react"
const Context = createContext(null)
const DemoUseContext = () => {
const [n, setN] = useState(0)
return (
<Context.Provider value={{ n, setN }}>
<Father />
<Son />
</Context.Provider>
)
}
const Father = () => {
const { n, setN } = useContext(Context)
return (
<>
<div>我是爸爸{n}</div>
<button onClick={() => setN(n => n + 1)}>爸爸按钮+1</button>
</>
)
}
const Son = () => {
const { n, setN } = useContext(Context)
return (
<>
<div>我是儿子{n}</div>
<button onClick={() => setN(n => n - 1)}>儿子按钮-1</button>
</>
)
}
export default DemoUseContext
四、useEffect和useLayoutEffect
步骤
- 导入
import { useEffect, useLayoutEffect } from "react"
- 每次都执行
useEffect(()=>{})
- 第一次渲染执行
useEffect(()=>{},[])
- 在某个值变化的时候执行
useEffect(()=>{},[n])
- 在页面渲染前执行
useLayoutEffect(()=>{})
代码示例
import React, {useState, useEffect, useLayoutEffect} from "react"
const DemoUseEffect = () => {
const [display, setDisplay] = useState(true)
const [n, setN] = useState(0)
useEffect(() => {
console.log("我每次都执行")
})
useEffect(() => {
console.log("我只在第一次执行")
return () => {
console.log("我只在销毁的时候执行")
}
}, [])
useEffect(() => {
console.log("我只在n变化执行")
}, [n])
useLayoutEffect(() => {
console.log("我是在页面渲染前就执行结束")
})
return (
<>
{display ? <div>{n}</div> : null}
<button onClick={() => setN(n => n + 5)}>+5</button>
<button onClick={() => {
setDisplay(display => !display)
}}>消灭n
</button>
</>
)
}
export default DemoUseEffect
五、memo&useMemo&useCallback
步骤
- 导入
import React, {useMemo, useState, memo, useEffect, useCallback} from "react"
- memo包住不需要重新渲染的组件函数
const Childer = memo((props) => {
console.log("我是孩子,我不想执行")
return (
<>
<div>我是孩子 {props.childer}</div>
</>
)
})
- useMemo包住防止因对象地址变化而导致的误渲染
const childClick = useMemo(() => {
return () => {
}
}, [childer])
代码示例
import React, {useMemo, useState, memo, useEffect, useCallback} from "react"
const DemoUseMemoAndUseCallback = () => {
const [n, setN] = useState(0)
const [childer, setChilder] = useState(0)
useEffect(() => {
console.log("我变化了")
}, [n])
// 使用useMemo阻止因为对象地址变化而重新执行
const childClick = useMemo(() => {
return () => {
}
}, [childer])
// 等同于useMemo,比useMemo简单
const childClick2 = useCallback(() => {
})
return (
<>
<div>{n}</div>
<Childer childer={childer} childClick={childClick} childClick2={childClick2}/>
<button onClick={() => setN(n => n + 10)}>+10</button>
</>
)
}
// 使用memo阻止子组件state没改变,因父组件属性改变而重新渲染
const Childer = memo((props) => {
console.log("我是孩子,我不想执行")
return (
<>
<div>我是孩子 {props.childer}</div>
</>
)
})
export default DemoUseMemoAndUseCallback
六、useRef
步骤
- 导入
import { useRef } from "react"
- 声明变量
const count = useRef(0)
- 使用/修改值
count.current += 1
代码示例
import React, {useEffect, useRef, useState} from "react"
const DemoUseRef = () => {
const count = useRef(0)
const [n, setN] = useState(0)
useEffect(() => {
count.current += 1
console.log("第" + count.current + "执行")
})
return (
<>
<div>{n}</div>
<button onClick={() => setN(n => n + 1)}>n+1</button>
</>
)
}
export default DemoUseRef
七、useImperativeHandle
步骤
- 导入
import { useImperativeHandle } from "react"
- 在父组件创建ref
const buttonRef = useRef()
- 传递给子组件
<button ref={buttonRef}>按钮</button>
- 子组件接收并对ref进行修改后返还出去
useImperativeHandle(ref, ()=>{
return {
x: ()=>console.log(1)
}
})
代码示例
import React, {forwardRef, useRef, useEffect, useImperativeHandle} from "react"
const DemoImperativeHandle = () => {
const buttonRef = useRef()
useEffect(() => {
console.log(buttonRef)
})
return (<>
<Son ref={buttonRef} onClick={() => console.log(buttonRef.current.x())}>按钮</Son>
</>)
}
const Son = forwardRef((props, ref) => {
const realRef = useRef()
useImperativeHandle(ref, () => {
return {
x: () => {
console.log(1)
},
ref: realRef
}
})
return (<>
<button ref={realRef} {...props}/>
</>)
})
export default DemoImperativeHandle
八、forwardRef
步骤
- 导入
import { forwardRef, useRef } from "react"
- 创建ref
const ref = useRef(null)
- 向组件传ref
<ChildNode ref={ref}>按钮</ChildNode>
- 使用forwardRef接收ref
const ChildNode = forwardRef((props, ref) => {
return (
<>
<button ref={ref} onClick={() => console.log(ref)}>{props.children}</button>
</>
)
})
代码示例
import React, {forwardRef, useRef} from "react"
const DemoForwardRef = () => {
const ref = useRef(null)
return (
<>
<div>我是本身的元素</div>
<ChildNode ref={ref}>按钮</ChildNode>
</>
)
}
const ChildNode = forwardRef((props, ref) => {
return (
<>
<button ref={ref} onClick={() => console.log(ref)}>{props.children}</button>
</>
)
})
export default DemoForwardRef
拓展一、useContext&useReducer代替Redux
步骤
- 创建Store数据仓库
cosnt store = {user: null, books: null, movies}
- 创建reducer行为操作列表
const reducer = (state, action) => {
switch (action.type) {
case "setUser":
return {...state, user: action.user}
case "setBooks":
return {...state, books: action.books}
case "setMovies":
return {...state, movies: action.movies}
default:
throw new Error("位置类型")
}
}
- 创建Context
const Context = createContext(null)
- 创建读写的API
const [state, dispatch] = useReducer(reducer, store)
- 定义作用域
<Context.Provider value={{state, dispatch}}>
<User/>
<Books/>
<Movies/>
</Context.Provider>
- 使用传递的数据
const {state, dispatch} = useContext(Context)
- 对数据进行操作
读
<div>{state.user.name}</div>
写
dispatch({type: "setUser", user: 数据})
代码示例
import React, {useContext, useEffect, useReducer, createContext} from "react"
// 数据仓库
const store = {
user: null,
books: null,
movies: null
}
// 行为类型
const reducer = (state, action) => {
switch (action.type) {
case "setUser":
return {...state, user: action.user}
case "setBooks":
return {...state, books: action.books}
case "setMovies":
return {...state, movies: action.movies}
default:
throw new Error("位置类型")
}
}
// 创建Context
const Context = createContext(null)
const DemoContextReducer = () => {
// 创建数据读写的API
const [state, dispatch] = useReducer(reducer, store)
return (
<Context.Provider value={{state, dispatch}}>
<User/>
<Books/>
<Movies/>
</Context.Provider>
)
}
const User = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/user").then(user => {
dispatch({type: "setUser", user})
console.log(user)
})
}, [])
return (
<>
<h3>姓名</h3>
{state.user ? <div>{state.user.name}</div> : null}
</>
)
}
const Books = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/books").then(books => {
dispatch({type: "setBooks", books})
})
}, [])
return (
<>
<h3>书籍</h3>
{state.books ? state.books.map(book => (<div key={book.id}>{book.name}</div>)) : null}
</>
)
}
const Movies = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/movies").then(movies => {
dispatch({type: "setMovies", movies: movies})
})
}, [])
return (
<div>
<h3>电影</h3>
{state.movies ? state.movies.map(item => <div key={item.id}>{item.name}</div>) : null}
</div>
)
}
export default DemoContextReducer
// 模拟请求数据
function ajax(path) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (path === "/user") {
resolve({
id: 1,
name: "梁又文"
})
} else if (path === "/books") {
resolve([{
id: 1,
name: "我是一本好书"
}, {
id: 2,
name: "我是一本坏书"
}])
} else if (path === "/movies") {
resolve([{
id: 1,
name: "最时间的尽头"
}, {
id: 2,
name: "八百"
}])
}
}, 3000)
})
}
拓展二、自定义hook
代码示例
useList
import {useState} from "react"
const useList = () => {
const [list, setList] = useState(0)
return ({
list: list,
setList: setList
})
}
export default useList
DemoCustomHook
import React from "react"
import useList from "./hooks/useList"
const DemoCustomHook = () => {
const {list, setList} = useList()
return (
<>
<div>{list}</div>
<button onClick={() => setList(n => n + 10)}>+10</button>
</>
)
}
export default DemoCustomHook