教你react中如何理解usestate、useEffect副作用、useRef标识和useContext
目录
- 1.usestate
- 1.1一般使用
- 1.2 useState回调函数作为参数
- 2.useEffect副作用
- 2.1 useEffect副作用及其使用
- 2.2 useEffect清理副作用
- 2.3 useEffect发送网络请求
- 3.自定义hook函数
- 4.useRef的使用
- 5.useContext的使用
1.usestate
1.1一般使用
注意:useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值。
其实与vue中的ref和reactive一样,通过useState获取到的数据可以实现组件视图实时交互,而普通定义的数据仅仅在业务中使用。
使用规则:
1.每个useState 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态 。
2. 只能出现在函数组件或者其他hook函数中 。
3. 不能嵌套在if/for/其它函数中(react按照hooks的调用顺序识别每一个hook)。
import { useState } from 'react' function App() { const [count, setCount] = useState(0) // 在这里可以进行打印测试 console.log(count) return ( <button onClick={() => { setCount(count + 1) }}>{count}</button> ) } export default App
初始值为泛型时:
interface LayerCheckbox { name: string; checked?: boolean; value?: string[]; disabled?: boolean; children?: LayerCheckbox[]; indeterminate?: boolean; key: string; // gis layer key relevance?: string; } const [checkboxArr, setCheckboxArr] = useState<LayerCheckbox[]>([ name: '高清影像图', checked: true, key: LayerEnum.TILES_MAP, }, { name: '农场地块信息', checked: true, key: LayerEnum.FIELD_AREA, }, { name: '灌溉设备图层', checked: true, key: LayerEnum.DRAIN_IRRIGATE, }, { name: '农情设备图层', checked: true, key: LayerEnum.CONDITION_DEVICE, }, ]);
1.2 useState回调函数作为参数
场景: useState初始值在回调函数里通过计算处理等函数操作得到
const [name, setName] = useState(()=>{ // 编写计算逻辑 //return '计算之后的初始值' })
2.useEffect副作用
2.1 useEffect副作用及其使用
副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用(比如,手动修改 DOM)。
常见副作用:
1.数据请求 ajax发送
2.手动修改dom
3.localstorage操作
useEffect函数的作用就是为react函数组件提供副作用处理的!
代码如下(示例):
import { useEffect, useState } from 'react' function App() { const [count, setCount] = useState(0) useEffect(()=>{ // dom操作 document.title = `当前已点击了${count}次` }) return ( <button onClick={() => { setCount(count + 1) }}>{count}</button> ) } export default App
使用的三种场景:
1.不添加依赖项
组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行。
1)组件初始渲染
2)组件更新 (不管是哪个状态引起的更新)
useEffect(()=>{ console.log('副作用执行了') })
2.添加空数组
组件只在首次渲染时执行一次
useEffect(()=>{ console.log('副作用执行了') },[]) })
3.添加特定依赖项
副作用函数在首次渲染时执行,在依赖项(count)发生变化时重新执行。
function App() { const [count, setCount] = useState(0) const [name, setName] = useState('zs') useEffect(() => { console.log('副作用执行了') }, [count]) return ( <> <button onClick={() => { setCount(count + 1) }}>{count}</button> <button onClick={() => { setName('cp') }}>{name}</button> </> ) }
只要是 useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组[count]中,如果不添加依赖项就会有bug出现。
2.2 useEffect清理副作用
如果想要清理副作用 可以在副作用函数中的末尾return一个新的函数,在新的函数中编写清理副作用的逻辑。
注意执行时机为:
1.组件卸载时自动执行
2.组件更新时(count一变时),下一个useEffect副作用函数执行之前自动执行
import { useEffect, useState } from "react" const App = () => { const [count, setCount] = useState(0) //页面初始化就执行一次,执行后count+1,依赖count变化,又来执行一次,此刻组件更新了,因此会清除副作用 useEffect(() => { const timerId = setInterval(() => { setCount(count + 1) }, 1000) return () => { // 用来清理副作用的事情 clearInterval(timerId) } }, [count]) return ( <div> {count} </div> ) } export default App
2.3 useEffect发送网络请求
在内部单独定义一个函数,然后把这个函数包装成同步或者异步
useEffect(()=>{ async function fetchData(){ const res = await axios.get('http://geek.itheima.net/v1_0/channels') console.log(res) } },[])
3.自定义hook函数
useState与useEffect都属于hook中的函数,那么也可以自己定义hook函数,利用useState和useEffect来实现自定义的hook函数,以便在其他地方调用。如:自定义一个hook函数,实现获取滚动距离Y。在其他地方调用此函数,就可以拿到这个y进行渲染或其他处理操作。
//自定义hook import { useState } from "react" export function useWindowScroll () { const [y, setY] = useState(0) window.addEventListener('scroll', () => { const h = document.documentElement.scrollTop setY(h) }) return [y] //调用区 import {useWindowScroll } from './hoooks/useWindowScroll ' const [y] = useWindowScroll () return( <div> {y} </div> )
自定义一个hook函数,监听依赖项(messge),实现一个功能(存储带本地):
//hook函数 import { useEffect, useState } from 'react' //message可以通过自定义传入默认初始值 export function useLocalStorage (key, defaultValue) { const [message, setMessage] = useState(defaultValue) // 每次只要message变化 就会自动同步到本地ls useEffect(() => { window.localStorage.setItem(key, message) }, [message, key]) return [message, setMessage] } //调用区 import {useLocalStorage } from './hoooks/useLocalStorage ' const [messge,setMessage] = useLocalStorage ('hook-key','阿飞') //初始值是 阿飞,5秒钟后变成 cp setTimeout(()=>{ setMessage('cp') },5000)
4.useRef的使用
useRef能在函数组件中获取真实的dom元素对象或者是组件对象。
首先执行 useRef 函数并传入null,返回值为一个对象内部有一个current属性存放拿到的dom对象(组件实例),在使用时通过ref 绑定 要获取的元素或者组件。
1)获取dom <dom名 ref={ h1Ref }>
import { useEffect, useRef } from 'react' function App() { const h1Ref = useRef(null) useEffect(() => { console.log(h1Ref) },[]) return ( <div> <h1 ref={ h1Ref }>this is h1</h1> </div> ) } export default App
2)获取组件实例 <组件名 ref={ h1Foo }>
//类组件 class Foo extends React.Component { sayHi = () => { console.log('say hi') } render(){ return <div>Foo</div> } } export default Foo //获取组件实例 import { useEffect, useRef } from 'react' import Foo from './Foo' function App() { const h1Foo = useRef(null) useEffect(() => { console.log(h1Foo) }, []) return ( <div> <Foo ref={ h1Foo } /></div> ) } export default App
5.useContext的使用
实现步骤:
1.使用createContext 创建Context对象
2.在顶层组件通过Provider 提供数据
3.在底层组件通过useContext函数获取数据
import { createContext, useContext } from 'react' // 创建Context对象 const Context = createContext() function A() { return <div>A中里面包裹C组件<C/></div> } function C() { // 底层组件通过useContext函数获取数据 const name = useContext(Context) return <div>C中{name}</div> } function App() { return ( // 顶层组件通过Provider 提供数据 <Context.Provider value={'this is name'}> <div><Foo/></div> </Context.Provider> ) } export default App
一样地,在顶层组件中Context.Provider这个value,然后在C组件中消费接受数据,由于A组件下面包裹着C组件,当A组件中执行C组件时,可以看到里面可以拿到value数据。
实际还是在“被包裹的组件(C)”中消费接收数据。
不论中间隔着几层,谁发数据谁provider,谁收数据谁useContext。
到此这篇关于react中如何理解usestate、useEffect副作用、useRef标识和useContext的文章就介绍到这了,更多相关react usestate useEffect副作用 useRef标识和useContext内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!