useState
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<p>当前计数器的值为:{count}</p>
<button onClick={handleClick}>增加计数器</button>
</div>
);
}功能:
用于在函数组件中定义和管理状态。
用法:
const [count, setCount] = useState(0)
设置一个count用来存储计数器的状态,使用setCount修改count所存储的状态。
useState(0)中的0为初始状态,即在未修改状态之前,count的值为0。注意:
1.在使用setCount修改状态后,并不能立即拿到修改的状态,而是在React重新渲染组件后,将新的状态应用到count变量上。即count 的改变会在下一次组件渲染时生效。
这是因为React 使用"批处理"的机制来优化状态更新。即在同一个事件处理函数中多次调用 setCount,React 会将这些更新合并为一个单独的更新,并进行一次重新渲染。
2.如果修改的状态结构是对象,那么需要将原对象进行复制,在修改
//添加一个c:3
const [obj, setObj] = useState({a:1,b:2});
setObj(...obj,{c:3})如果是多层嵌套,修改里面的内容使用…进行浅拷贝可能会有一些复杂,此时我们可以使用Immer来简化更新逻辑
const person = {
name:'huahua',
age:2,
hobby:{
sing:'abc',
play:'guitar'
}
}
const [obj, setObj] = useState(person)
//这里我们将‘guitar’改为‘piano’
setObj({
...person, //复制person
hobby:{ //替换hobby
...person.hobby, //复制hobby
play:'piano' //替换为‘piano’
}
})
//使用Immer修改
//首先需要安装依赖 npm install use-immer
const [obj, updateObj] = useImmer(person)
updateObj(draft => {
draft.hobby.play='piano'
})useRef
function App() {
const inputRef = useRef(null)
const handleClick = () => {
console.log(inputRef);
}
return (
<>
<input type="text" ref={inputRef}/>
<button onClick={handleClick}></button>
</>
)
}

功能:
获取DOM元素。
用法:
const inputRef = useRef(null)
定义一个变量inputRef,使用useRef并将初始值设置为null。在需要获取的DOM元素上绑定ref={inputRef}。
使用 inputRef.current即可获取DOM,使用inputRef.current.value即可获取当前输入的值。
注意:
使用useRef只有在组件渲染完成即DOM生成之后,才可以获取到DOM。
思考:
e获取到输入框的值之后,是否可以使用inputRef.current.value动态渲染页面呢?
更改一下上面的代码,点击按钮时,将输入框的内容展示到页面上
function App() {
const inputRef = useRef(null)
const [showRefValue, setSHowRefValue] = useState(false)
const handleClick = () => {
console.log(inputRef);
setSHowRefValue(true)
}
return (
<>
<input type="text" ref={inputRef}/>
<button onClick={handleClick}>按钮</button>
{
showRefValue && <div>{inputRef.current.value}</div>
}
</>
)
}可以看到,第一次是可以正确的展示的。

我们修改输入框的值,并再次点击按钮,123并没有变成aaa。
这是因为修改 countRef.current 不会触发组件的重新渲染,因此 useRef 返回的引用对象在重新渲染时保持不变。
如果希望点击按钮时,将输入框的内容展示到页面上,我们可以使用useState将输入框的值进行存储。

总结:
获取表单的信息时,如果需要动态展示在页面上,使用useState;如果只是收集数据做一些逻辑性的操作,使用useRef。
useEffect
功能:
用于在react组件中创建由渲染本身引起的操作(ajax请求,更改DOM等)
const url = 'http://geek.itheima.net/v1_0/channels'
useEffect(()=>{
async function getList() {
const res = await fetch(url)
const list = await res.json()
console.log(list);
}
getList()
},[])用法:
useEffect接收两个参数,第一个参数是回调函数用于执行一些操作;第二个参数是依赖项数组,用于触发回调函数的执行时机。
不同的依赖项会导致不同回调执行时间
这里我们写入的依赖项是空数组,所以该回调只在初始渲染执行一次。
function App() {
const [count, setCount] = useState(0)
useEffect(()=>{
console.log('useEffect执行');
})
return (
<div>
count:{count}
<br />
<button onClick={()=>setCount(count+1)}>+</button>
</div>
)
}这里我们没有写入依赖项,回调函数在组件初始渲染和组件更新时执行。
(初始化执行)

(更新count状态重新渲染组件,useEffect会再次执行)

(将依赖项变为count)
function App() {
const [count, setCount] = useState(0)
useEffect(()=>{
console.log('useEffect执行');
}, [count])
return (
<div>
count:{count}
<br />
<button onClick={()=>setCount(count+1)}>+</button>
</div>
)
}当指定依赖项时,回调函数在组件初始渲染和依赖项发生变化时执行。
(初始化执行一次)

(count发生变化 useEffect重新执行)

注意:
这里不写入依赖项和将count作为依赖项产生的结果是一样的,这是因为本例中状态只有count。
当组件中有多个状态发生改变的时候,无依赖项的回调函数依旧会重新执行;而将count作为依赖项,只有count发生变化(无论组件是否重新渲染)时会重新执行回调。
使用useEffect清除副作用
在组件卸载时我们通常需要清除一些副作用,比如:计时器(不及时清理可能会导致内存泄漏)。
副作用操作:指由渲染本身引起的对接组件外部的操作
//在卸载组件Son时清除定时器
function Son(){
useEffect(()=>{
setInterval(()=>{
console.log('执行useEffect');
},1000)
})
return(
<div>son component</div>
)
}
function App() {
const [show, setShow] = useState(true)
return (
<>
{show && <Son />}
<button onClick={()=>setShow(false)}>卸载son组件</button>
</>
)
}这里我们没有去清除副作用即未将定时器清除,所以在Son组件卸载之后,定时器依旧在执行。


这里我们在Son组件卸载之后去清除定时器,可以看到定时器将不在执行。
(useEffect中的return会在组件卸载时自动执行,除了在卸载时还有一些其他的执行时机,但不常用。)
function Son(){
useEffect(()=>{
const timer = setInterval(()=>{
console.log('执行useEffect');
},1000)
return ()=>{
clearInterval(timer)
}
})
return(
<div>son component</div>
)
}
function App() {
const [show, setShow] = useState(true)
return (
<>
{show && <Son />}
<button onClick={()=>setShow(false)}>卸载son组件</button>
</>
)
}

自定义hook
为了提高部分功能的复用,便于后期维护,我们通常会自定义一些hook进行逻辑复用
//展示App component的显示与隐藏
function App() {
const [show, setShow] = useState(true)
const handleShow = () => {
setShow(!show)
}
return (
<>
{show && <div>App component</div>}
<button onClick={handleShow}>show</button>
</>
)
}将展示与隐藏的逻辑抽离出来,进行自定义hook。
function useShow(){
const [show, setShow] = useState(true)
const handleShow = () => setShow(!show)
return {show, handleShow}
}
function App() {
const {show, handleShow} = useShow()
return (
<>
{show && <div>App component</div>}
<button onClick={handleShow}>show</button>
</>
)
}用法:
1.声明一个以use开头的函数
2.在函数体内封装需要复用的逻辑
3.将组件中用到的状态使用return返回出去
4.在使用到自定义hook的组件中执行该函数,解构出需要的状态进行使用
















