useState
- 使用useState可以让函数式组件也能拥有状态(state)
- 语法:
const [xxx, setXxx] = React.useState(initValue)
initValue是初始值 - useState()说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数 - setXxx()2种写法:
// 1 . setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
const [count,setCount] = React.useState(0)
function add(){
setCount(count+1)
}
复制代码
// 2 . 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
const [count,setCount] = React.useState(0)
function add(){
setCount(value=>value+1)
}
复制代码
useEffect
- 使用useEffect,能让函数式组件完成类似生命周期的功能
语法和说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 相当于componentWillUnmount
}
}, [stateValue])
// 如果指定的是[], 回调函数只会在第一次render()后执行
// 如果没有的话挂载和每次更新都会执行
复制代码
- useEffect第一个参数的return后面是一个函数,该函数相当于
componentWillUnmount
- useEffect第二个参数不填的话,那么每次渲染都会执行,相当于
componentDidUpdate
- useEffect第二个参数是空数组的话,相当于
componentDidMount
- useEffect第二个参数可以指定某个属性变化了之后再执行
const [count, setcount] = React.useState(0)
const [name, setname] = React.useState('zxx')
React.useEffect(()=>{
console.log('count变化了才执行,name变化不执行')
},[count])
复制代码
useLayoutEffect
- 用法和
useEffect
一样,但是效果有略微的差别 useLayoutEffect
的执行会先于useEffect
,所以想要修改组件元素样式建议用useLayoutEffect
useContext
useContext
可以帮助我们跨越组件层级直接传递变量,实现共享- 首先在父组件中
// 想要通过context传递两个数据
import React ,{useContext}from 'react'
const CountContext = React.createContext()
const NameContext = React.createContext()
export default function Father() {
return (
<div>
<CountContext.Provider value={15}>
<NameContext.Provider value={'sss'}>
<Son/>
</NameContext.Provider>
</CountContext.Provider>
</div>
)
}
复制代码
- 在后代组件中接受
function Son(){
//useContext 的参数必须是 context 对象本身,没有的话就自己导入
const countInfo = useContext(CountContext)
const nameInfo = useContext(NameContext)
return (
<div>
<h2>Header组件</h2>
<p>{countInfo}</p>
<p>{nameInfo}</p>
</div>
)
}
复制代码
useReducer
useReducer
仅仅是useState的一种替代方案。如果state
处理逻辑比较复杂,我们可以用useReducer
来拆分
const [状态,dispatch] = useReducer(reducer,初始化状态的值)
import React ,{useReducer}from 'react'
// 第一步创建reducer,接受两个参数state和action
function reducer(state,action){
switch (action.type) {
case 'increment':
return {...state,num:state.num+1}
case 'decrement':
return {...state,num:state.num-1}
default:
throw new Error();
}
}
function Home(){
// 使用useReducer
const [state,dispatch] = useReducer(reducer,{num:0})
return (
<div>
<h2>Header数据:{state.num}</h2>
{/*派发action*/}
<button onClick={()=>dispatch({type:'decrement'})}>-1</button>
<button onClick={()=>dispatch({type:'increment'})}>+1</button>
</div>
)
}
function About(){
const [state,dispatch] = useReducer(reducer,{num:25})
return(
<>
<h2>About数据:{state.num}</h2>
<button onClick={()=>dispatch({type:'decrement'})}>-1</button>
<button onClick={()=>dispatch({type:'increment'})}>+1</button>
</>
)
}
export default function App() {
return (
<div>
<Home></Home>
<About></About>
</div>
)
}
复制代码
useCallback
useCallback
实际的目的是为了进行性能优化
useCallback
会返回一个函数的memoized值- 在依赖不变的情况下,多次定义的时候,返回的值是相同的
搭配
memo
使用:当不使用memo
的时候,父组件重新渲染,子组件必定重新渲染,所以使用memo(子组件),可以避免这个情况发生
import React,{useState,memo,useCallback} from 'react'
// 没使用useCallback的时候,每次增加或者减少,所有的组件都会重新渲染
function Home(props){
console.log("HOME渲染了");
return(
<div>
<p>Home</p>
<button onClick={()=>props.handle()}>减小</button>
</div>
)
}
function About(props){
console.log("ABOUT渲染了");
return(
<div>
<p>About</p>
<button onClick={()=>props.handle()}>增加</button>
</div>
)
}
const MemoHome = memo(Home)
const MemoAbout = memo(About)
export default function App() {
console.log("APP渲染了");
const [numState,setNum] = useState(12)
const [ageState,setAge] = useState(2)
// 只有ageState变化时候,sub这个函数才会变化
const sub = useCallback(
() => {
setAge(ageState-1)
},[ageState],
)
// 只有numState变化时候,add这个函数才会变化
const add = useCallback(
() => {
setNum(numState+2)
},[numState],
)
return (
<div>
<p>num:{numState}</p>
<p>age:{ageState}</p>
<hr />
<MemoHome handle={sub}/>
<MemoAbout handle={add}/>
</div>
)
复制代码
使用场景:将一个组件中的函数,传递给子组件进行回调使用时,使用useCallback对函数进行处理
useMemo
useCallback
实际的目的也是为了进行性能优化
- 使用场景一:
// 每次点击按钮Home组件都会重新渲染,因为App组件重新渲染导致person的内存地址变化
import React, { memo,useState } from 'react'
const Home = memo((props)=>{
console.log('Home渲染');
return (
<h2>name:{props.person.name}--age:{props.person.age}</h2>
)
})
export default function App() {
const [show, setshow] = useState(false)
let person = {name:'zx',age:15}
return (
<div>
<Home person={person}/>
<button onClick={()=>setshow(!show)}>changeShow</button>
</div>
)
}
复制代码
- 场景一解决方法:
import React, { memo,useMemo,useState} from 'react'
const Home = memo((props)=>{
console.log('Home渲染');
return (
<h2>name:{props.person.name}--age:{props.person.age}</h2>
)
})
export default function App() {
const [show, setshow] = useState(false)
let person = useMemo(() => {
return {name:'zx',age:15}
}, [])
return (
<div>
<Home person={person}/>
<button onClick={()=>setshow(!show)}>changeShow</button>
</div>
)
}
复制代码
- 使用场景二
- 如果没有使用useMemo,返回函数的时候,每次App重新渲染都会让getData这个函数重新调用
import React,{useMemo, useState} from 'react'
function getData(){
console.log('getData被调用了');
let data = 0
for(let i=0;i<1000;i++){
data+=i
}
return data
}
export default function App() {
console.log('App组件被渲染了');
const [numState,setNum] = useState(10)
const [ageState] = useState(55)
// const data = getData()
// 通过useMemo可以使得getData不会被重复调用
const data = useMemo(()=>{
return getData()
},[])
return (
<div>
<h2>num:{numState}</h2>
<h2>age:{ageState}</h2>
{/* 修改numState的时候,getData会被重新调用 */}
<button onClick={()=>{setNum(numState+1)}}>修改num</button>
<h2>data:{data}</h2>
</div>
)
}
复制代码
useRef
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END