react Hooks
一.state hook
1.useState的使用
import React, { useState } from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
const App = () => {
const [count, setCount] = useState(0)
const onClick = (params) => {
setCount(count + 1)
console.log(count)
}
return (
<div>
<div>{count}</div>
<button onClick={() => onClick()}>button</button>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<App />
)
注意
setCount是异步的,console.log(count)会先执行,如果想拿到最新的count,可以使用回调函数的写法。
两种方式
const onClick = (params) => {
setCount((count) => count + 1)
}
console.log(count)
const onClick = (params) => {
setCount((count) => {
count++
console.log(count)
return count
})
}
只有在count的值改变时,才会重新渲染。如果setCount中为空对象,则会重新渲染,
因为对象之间对比的是引用即地址,每次设置的地址不同,当然会重新渲染。
如果初始值为一个对象
import React, { useState } from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
const App = () => {
const [state, setState] = useState({type: 'add', value: 0})
const onClick = (params) => {
setState((prevState) => {
if(prevState.type === 'add'){
return {
...prevState,
value: prevState.value + 1
}
}
return prevState
})
}
return (
<div>
<div>{state.value}</div>
<button onClick={() => onClick()}>button</button>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<App />
)
2.useReducer使用
在参数是一个对象时考虑使用useReducer
import React, { useReducer } from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
const App = (params) => {
const [count, countDispatch] = useReducer(countReducer, 0)
const countReducer = (state, action) => {
switch(action.type){
case 'add':
return state + 1
case 'minus':
return state - 1
default:
return state
}
}
const onClick = (params) => {
countDispatch({type: 'add'})//add描述当前行为
//countDispatch({type: 'minus'})
}
return (
<div>
<div>{count}</div>
<button onClick={() => onClick()}>button</button>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<App />
)
二. useEffect使用
1.副作用
·引用外部变量,调用外部函数
·拿外部变量,包括修改全局变量(window),修改DOM操作,Ajax请求,计时器,存储相关
·和外部变量的交互
2.用法
useEffect在初次渲染以后执行,会在组件完成更新以后执行,每次都会执行
const App = (params) => {
const [count, setCount] = useState(0)
console.log("render")
useEffect(() => {
console.log("effect")
})
return (
<div>
<div>{count}</div>
<button onClick={() => onClick()}>button</button>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<App />
)
具体的时间点以页面的真实DOM加载为准,在componentDidUpdate真实DOM构建以后,然后执行useEffect,因为useEffect是异步的。
清除Effect
useEffect(() => {
console.log("useEffect")
return () => {
console.log("clear Effect")
}
})
执行顺序为 render -> clear Effect -> useEffect
清理函数在副作用函数之前运行,在组件销毁的时候同样也会执行
如果只希望在初次渲染时执行,不希望在更新时执行,可以使用依赖项[]
useEffect(() => {
console.log("开启计时器")
let timer = setInterval(() => {
console.log("进入计时器")
setCount(count => count + 1)//箭头函数
//setCount(count + 1)
},1000)
return () => {
console.log("清除计时器")
clearInterval(timer)
}
},[])
用到了count依赖项,count改变useEffect重新运行,但是又会重新开启新的计时器,最好还是使用箭头函数的方法。
1.指定当前effect函数所需的依赖项。
2.依赖是空数组,在初次渲染和卸载的时候执行。
3.有依赖项,并且依赖项不一直时,会重新执行。
练习
自定义hook
const useCount = params => {
const [count,setCount] = useState(0)
useEffect(() => {
document.title = `You clicked ${count} times`
console.log("title")
})
return [count,setCount]
}
const [count,setCount] = useCount()
console.log("render")
useEffect(() => {
console.log("effect")
})
三.useContext
函数组件用法
import React, {Component, createContext,useContext} from 'react'
import ReactDOM from 'react-dom/client'
const AppContent = createContext()
const Baz = (props) => {
const value = useContext(AppContent)
return (
<div>{value}</div>
)
}
const App = (params) => {
return (
<AppContext.Provider value="xiaoxia">
<Baz />
</AppContext.Provider>
)
}
四.useRef
const Foo = (params) => {
const inputRef = useRef()
const onClick = (params) => {
inputRef.current.focus()
}
return (
<div>
<input type="text" ref={inputRef}/>
<button onClick={onClick}>聚焦</button>
</div>
)
}
const App = (params) => {
return (
<div>
<Foo />
</div>
)
}
转发Ref函数组件用法
const Foo = forwardRef((params) => {
//const inputRef = useRef()
const onClick = (params) => {
inputRef.current.focus()
}
return (
<div>
<input type="text" ref={inputRef}/>
<button onClick={onClick}>聚焦</button>
</div>
)
})
const App = (params) => {
const inputRef = createRef()
const onClick = (params) => {
inputRef.current.focus()
}
return (
<div>
<Foo ref={inputRef}/>
<button onClick={onClick}>父组件</button>
</div>
)
}
五.useCallback useMemo
import React, {useState, useMemo,useCallback,memo} from 'react'
const Foo = memo(props => {
return (
<di>{props.count}</di>
)
})
function App(){
const [range,setRange] = useState({min:0,max: 10000})
cosnt [count,setCount] = useState(0)
const render = useCallback((params) => {
let list = []
console.log(1)
for(let i = 0; i <range.max; i++){
list.push(<li key={i}>{i}</li>)
}
return list
},[range])
return (
<div>
<h1>{count}</h1>
<button onClick={()=>{setCount(count+1)}}>add</button>
<Foo render={render}/>
</div>
)
}
评论区