import React, { useEffect, useState } from ‘react’;
hook 是react 16.8的新增特性 ,他可以让你不在编写class的情况下shiystate以及react的特性 Hooks的出现,首先解决了以下问题:
- 告别了令人疑惑的生命周期
- 告别类组件中烦人的this
- 告别繁重的类组件,回归到了熟悉的函数组件
react 整个思想上面的转变,从“面向对象”的思想转为“函数式编程”,所以你会突然发现会多了一些新概念 比如:纯函数,副作用,柯里化,高阶函数等概念
useState
1.基础使用
import { useState } from 'react' function App() { // 参数:状态初始值比如,传入 0 表示该状态的初始值为 0 // 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState) const [count, setCount] = useState(0); // 修改count内容 const modifyEvent = () => { setCount(count + 1) } return ( <button onClick={() => modifyEvent()}>{count}</button> ) } export default App
2.状态的读取和修改执行流程与逻辑
读取状态:该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用 修改状态:
1.setCount是一个函数,参数表示最新的状态值
2.调用该函数后,将使用新值替换旧值
3.修改状态后,由于状态发生变化,会引起试图变化 注意
事项:修改状态的时候,一定要使用新的状态替换旧的状态,不能直接修改旧的状态,尤其是引用类型
3. 组件的更新过程
函数组件使用 useState hook 后的执行过程,以及状态值的变化
1.组件第一次渲染
- 从头开始执行该组件中的代码逻辑
- 调用 useState(0) 将传入的参数作为状态初始值,即:0
- 渲染组件,此时,获取到的状态 count 值为: 0
2.组件第二次渲染
- 点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
- 组件重新渲染时,会再次执行该组件中的代码逻辑
- 再次调用 useState(0) ,此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
- 再次渲染组件,此时,获取到的状态 count 值为:1
注:useState 的初始值(参数)只会在组件第一次渲染时生效。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值
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
4.使用规则
1.useState 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态
function List(){ // 以字符串为初始值 const [name, setName] = useState('cp') // 以数组为初始值 const [list,setList] = useState([]) }
2.useState 注意事项
- 只能出现在函数组件或者其他hook函数中
- 能嵌套在if/for/其它函数中(react按照hooks的调用顺序识别每一个hook)
useEffect
1.理解函数副作用
副作用是相对于主作用来说的,一个函数除了主作用,其他的作用就是副作用。对于 React 组件来说,主作用就是根据数据(state/props)渲染 UI,除此之外都是副作用(比如,手动修改 DOM) 常见的副作用:
- 数据请求 ajax发送
- 手动修改dom
- localstorage操作
useEffect函数的作用就是为react函数组件提供副作用处理的数据和逻辑,从而修改UI和用户交互等一种方式。
2. 基础使用
下面案例说明,函数组件储存了当前state所有状态,函数初次就会触发他们两个的加载,另外当某一个发生改变了 useEffect和函数都会被重新执行加载
import { useEffect, useState } from 'react' function App() { const [count, setCount] = useState(0) useEffect(()=>{ // 修改了dom数据后 userffect函数被副作用重新执行 console.log('执行了副作用函数') }); // 函数组件也会被重新执行 console.log('函数组件被重新执行了') return ( <button onClick={() => { setCount(count + 1) }}>{count}</button> ) } export default App
3.useEffect依赖项和控制执行的时机
由于 组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行
添加空数组依赖
import { useEffect, useState } from 'react' function App() { const [count, setCount] = useState(0) useEffect(()=>{ // 修改了dom数据后 userffect函数不会在被触发,只有首次加载函数才会执行一次 console.log('执行了副作用函数') },[]); //修改了dom数据后 函数组件会被重新执行 console.log('函数组件被重新执行了') return ( <button onClick={() => { setCount(count + 1) }}>{count}</button> ) } export default App
添加特定项作为依赖
副作用函数在首次渲染时执行,在依赖项发生变化时重新执行
给useEffect添加特定的依赖项,当这个依赖性的state发生改变,useEffect与函数组件都会重新渲染被执行,由于第二个参数是依赖项所以是数组可以添加多个依赖项
没有useEffect添加的特定的依赖项,就不会触发useEffect函数,只会触发组件的渲染函数
function App() { const [count, setCount] = useState(0) const [name, setName] = useState('zs') useEffect(() => { console.log('副作用执行了') }, [count]) console.log('组件被执行了') return ( <> <button onClick={() => { setCount(count + 1) }}>{count}</button> <button onClick={() => { setName('cp') }}>{name}</button> </> ) }
清理副作用
function App() { const [count, setCount] = useState(0) const [name, setName] = useState('zs') useEffect(() => { console.log('副作用执行了') return () => { alert(1) console.log('执行了清楚副作用,组件卸载的时候执行') } }, [count]) console.log('组件被执行了') return ( <> <button onClick={() => { setCount(count + 1) }}>{count}</button> <button onClick={() => { setName('cp') }}>{name}</button> </> ) }
另外一般一个 useEffect 只用来处理一个功能,有多个功能时,建议使用多个 useEffect
useMemo(性能优化)
解决函数组件的性能问题,比如子组件重复执行问题,每次渲染都进行高开销的计算
// 子组件 function Sub(props) { console.log("Sub render"); let { number, onClick } = props return ( <button onClick={onClick}>{number}</button> ) } // 父组件 function Test() { let [value, setValue] = useState('') let [number, setNumber] = useState(0) const addClick = () => setNumber(number + 1) return <> <input type="text" value={value} onChange={(e) => setValue(e.target.value)} /> <Sub number={number} onClick={addClick} /> </> } export default Test;
子组件依赖的只有number ,理想情况下只希望number变化时触发子组件重新渲染
但实际是在输入框内的值发生变化,子组件也会重新渲染 如果子组件的逻辑较复杂,就是无意义的大量计算,浪费资源
// 子组件 function Sub(props) { console.log("Sub render"); let { number, onClick } = props return ( <button onClick={onClick}>{number}</button> ) } // 父组件 function Test() { let [value, setValue] = useState('') let [number, setNumber] = useState(0) const addClick = () => setNumber(number + 1); // 使用useMemo记住计算后的值,只有当依赖number变量发生变化,才会重新计算子组件内容 const MemoSub = useMemo( () => <Sub data={number} onClick={addClick} />, [number] // 只有 number 变化才重新计算 MenoSub ) return <> <input type="text" value={value} onChange={(e) => setValue(e.target.value)} /> {MemoSub} </> } export default Test;
useCallback(性能优化)
接收两个参数:回调函数和依赖项数组。回调函数是需要缓存的函数,依赖项数组用于确定何时需要重新创建函数实例。
当依赖项数组中的任何一个值发生变化时,useCallback 将返回一个新的函数实例,否则它将返回之前缓存的函数实例
import { useState, useCallback } from 'react'; function MyComponent() { const [count, setCount] = useState(0); // 使用 useCallback 缓存 handleClick 函数 const handleClick = useCallback(() => { setCount(count + 1); }, [count]); return ( <div> <p>You clicked {count} times</p> {/* 在按钮上使用缓存的 handleClick 函数 */} <button onClick={handleClick}>Click me</button> </div> ); }
在这个例子中,我们使用 useCallback 来缓存回调函数 handleClick, 将其缓存以避免在每次重新渲染组件时创建新的函数实例。
同时,在按钮上使用了缓存的 handleClick 函数,以确保点击按钮时调用的是缓存的函数实例。我们还将 count 添加到依赖项数组中,以确保每当 count 发生变化时,handleClick 都会被重新创建。
useCallback 和 useMomeo 的区别
1.useCallback 和 useMemo 都是用于性能优化的 React 钩子函数,它们都可以避免不必要的重新计算或重新渲染。虽然它们看起来很相似,但它们有几个重要的区别。
2.首先,useCallback 返回一个缓存的回调函数,而 useMemo 返回一个缓存的值。这意味着 useCallback 的主要作用是为一个函数创建缓存,而 useMemo 的主要作用是缓存一个值
3.最后,它们的使用场景也不同。useCallback 适用于优化回调函数,避免不必要的重新渲染,并传递给子组件。而 useMemo 适用于优化计算开销较大的值,如大型数组或对象的计算
useRef
useRef 可以缓存所有数据类型,更新的数据不会随着组件的重新渲染而重置,会一直保持最新状态的内容,
但是保存的数据类型 无法在ui渲染页面上使用,只能作为一个状态进行储存
也可以绑定给一个元素标签获取dom进行操作
function Test() { /* 保存 DOM */ const inputEl = useRef() const onClick = () => { console.log(inputEl); // 对象类型,只有一个 current 属性指向指定DOM inputEl.current.innerHTML = '2asdasd sd阿萨德' } return <div> <div ref={inputEl}></div> <button onClick={onClick}>click me!!!</button> <br /> </div> }
useContext
usecontext React 16.3本中新引入的一个特性,它可以让组件之间共享数据十分方便。它属于 React Context API(上下文API),可以让组件层级之间自由传递数据,而使用Context API可以极大地提高组件之间的可复用性。
使用 useContext以使组件树中的任何组件访问到 cntext值,无论它是何种层级的,而且更方便的是,不需要利用props行传递,而只需要一行代码即可
下面案例是同一组件下多个 子组件的上下文通讯
import React, { createContext, useContext } from 'react'; const ThemeContext = createContext('light') // 父组件 function Test() { return ( <ThemeContext.Provider value="dark"> <Toolbar theme="dark" /> </ThemeContext.Provider> ) } // 子组件 function Toolbar(props) { return ( // 中间的组件再也不必指明往下传递 theme 了。 <div> <Button /> </div> ) } // 子组件中的子组件 function Button() { // 指定 contextType 读取当前的 themecontext。 // React 会往上找到最近的 theme Provider,然后使用它的值。 // 在这个例子中,当前的 theme 值为 “dark”。 const theme = useContext(ThemeContext) return <button>{ theme }</button> }
垮文件使用usecontext 进行通讯
父组件
import React, { useState, createContext } from 'react' import Counter from './Counter' export const countContext = createContext() export default function Example4() { const [count, setCount] = useState(0) return ( <div> <p>你点击了{count}次</p> <button onClick={()=>{setCount(count+1)}}>点击</button> <countContext.Provider value={count}> <Counter /> </countContext.Provider> </div> ) }
子组件
import React, { useContext } from 'react' import { countContext } from './Example4' function Counter() { let count = useContext(countContext) return ( <div> <h2>{count}</h2> </div> ) } export default Counter
这样在多级组件使用就减少使用redux,useContext确实好用,起码跨级传递数据不用那么麻烦了
完结,有不足欢迎补充。
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容