一、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 += 1console.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("位置类型")}}// 创建Contextconst Context = createContext(null)const DemoContextReducer = () => {// 创建数据读写的APIconst [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
