1、useState
import { useState } from 'react'
function Home() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => {setCount(count + 1)}}>{count}</button>
</div>
)
}
export default Home
状态的读取和修改:
- useState传过来的参数,作为count的初始值
- [count, setCount]这里的写法是一个解构赋值,useState返回值是一个数组,名字可以自定义,但是顺序不能换
- setCount函数用来修改count值,不能直接修改原值,而且生成一个新值来替换旧值:setCount(基于原值计算得到的新值)
- count和setCount是一对,是绑在一起的,setCount只能用来修改对应的count值
组件更新:
useState初始值只在首次渲染生效,后续只要调用setCount整个组件中代码都会重新执行,此时的count每次拿到的都是最新值。
-
首次渲染:组件内部的代码会被执行一次,其中useState也会跟着执行,初始值只在首次渲染时生效
-
更新渲染:组件会再次渲染,函数会被再次执行,useState再次执行,得到的新的count值不是0而是修改之后的1,模板会用新值渲染
2、useState的回调函数
使用场景:参数只会再组件的初始渲染中起作用,后续渲染会被忽略,如果初始state需要通过计算才能获得,则可以传入一个函数,在函数中计算并返回初始的state,此函数只在初始渲染时被调用
import { useState } from 'react'
function Counter(props) {
const [count, setCount] = useState(() => {
return props.count
})
return (
<button onClick={() => {setCount(count + 1)}}>{count}</button>
)
}
function Home() {
return <Counter count={20}></Counter>
}
export default Home
useState注意重点
- useState的初始参数只会在组件首次渲染时使用,再次更新时会被忽略
- 每次通过setCount修改状态都会引起组件重新渲染
- useState不可以在除了函数组件之外的地方,比如分支语句,循环语句,内部函数中执行
- 如果初始值需要计算才能得到可以使用回调函数的写法来确定useState的初始值
3、useEffect
- 默认状态(无依赖项):组件初始化的时候先执行一次,等到每次数据修改组件更新再次执行(首次执行+每次组件更新执行)
- 添加一个空数组依赖项:组件只在初始化的时候执行一次(首次执行)
- 依赖特定项:组件初始化的时候执行一次,依赖的特定项发生变化会再次执行(首次执行+依赖项变化执行)
import { useState, useEffect } from 'react'
function Home() {
const [count, setCount] = useState(0)
useEffect(() => {
console.log('每次数据更新时都会执行')
})
useEffect(() => {
console.log('只在组件初次渲染的时候执行一次')
}, [])
useEffect(() => {
console.log('count改变的时候执行')
}, [count])
return (
<div>
<button onClick={() => {setCount(count + 1)}}>{count}</button>
</div>
)
}
export default Home
4、useEffect的回调函数
使用场景:在组件被销毁时,如果有些操作需要被清理,就可以使用特定语法,比如清理定时器
import { useState, useEffect } from 'react'
function Counter() {
useEffect(() => {
let timer = setInterval(() => {
console.log('定时器执行了')
}, 1000)
return () => {
// 清理定时器
clearInterval(timer)
}
}, [])
return <p>this is text</p>
}
function Home() {
const [flag, setFlag] = useState(true)
return (
<div>
{flag ? <Counter></Counter> : null}
<button onClick={() => setFlag(!flag)}>switch</button>
</div>
)
}
export default Home
5、useRef
通过ref绑定要获取的元素或者组件,执行useRef函数并传入null,返回值为一个对象,内部有一个current属性存放拿到的dom对象(组件实例)
- 注意:函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件
import { useEffect, useRef } from 'react'
function Home() {
const h1Ref = useRef(null)
// useEffect是在dom渲染之后才执行
useEffect(() => {
console.log(h1Ref)
}, [])
return (
<div>
<h1 ref={h1Ref}>this is h1</h1>
</div>
)
}
export default Home
6、useContext
实现步骤:使用createContext创建Context对象,在顶层组件通过Provider提供数据,在底层组件通过useContext函数获取数据
- const xxx = React.createContext();创建一个context
- <xxx.Provider value={[ num, setNum ]}>父组件设置要传递的值
- const [ num, setNum ] = React.useContext(xxx);子组件下使用
import { useContext, useState, createContext } from 'react'
const Context = createContext()
// 子组件A
function ComA() {
const [count, name] = useContext(Context)
return (
<div>
this is ComA
<h2>A组件中接受到的count:{count}</h2>
<h2>A组件中接受到的name:{name}</h2>
<ComB></ComB>
</div>
)
}
// 孙组件B
function ComB() {
const [count, name] = useContext(Context)
return (
<div>
<p>this is ComB</p>
<h2>B组件中接受到的count:{count}</h2>
<h2>B组件中接受到的name:{name}</h2>
</div>
)
}
// 父组件
function Home() {
const [count, setCount] = useState(20)
const [name, setName] = useState('Tom')
const change = () => {
setCount(count + 1)
setName('Jack')
}
return (
<Context.Provider value={[count, name]}>
<div>
<ComA></ComA>
<button onClick={change}>click</button>
</div>
</Context.Provider>
)
}
export default Home