当前位置: 首页 > news >正文

域名 空间 建网站深圳网站开发设计公司排名

域名 空间 建网站,深圳网站开发设计公司排名,zion小程序开发,上海集团网站建设价格为什么hook必须在组件内的顶层声明? 这是为了确保每次组件渲染时,Hooks 的调用顺序保持一致。React利用 hook 的调用顺序来跟踪各个 hook 的状态。每当一个函数组件被渲染时,所有的 hook 调用都是按照从上到下的顺序依次执行的。React 内部会…

为什么hook必须在组件内的顶层声明?

这是为了确保每次组件渲染时,Hooks 的调用顺序保持一致。React利用 hook 的调用顺序来跟踪各个 hook 的状态。每当一个函数组件被渲染时,所有的 hook 调用都是按照从上到下的顺序依次执行的。React 内部会维护一个状态列表,这个列表中的每个状态项都对应一个 hook 的调用,包括 useState、useEffect 等。当你调用 useState(initialValue) 时,React 会在内部为这个状态分配一个索引。该索引基于 hook 调用的顺序。例如,第一次调用 useState 时,它会在状态列表的第一个位置存储状态,第二次调用会在第二个位置存储,以此类推

考虑下面这个demo:

const Component = () => {const [count, setCount] = useState(0);const handleOfClick = () => setCount(count + 1);return <button onClick={setCount}>{count}</button>
}

Q:既然每次视图的更新都会重新执行整个函数,那必然会执行到const [count, setCount] = useState(0)这句代码。如果我在上一次更新中把count加到10,为什么在新的渲染周期中,React能记住这个10而不是传给useState的0呢?
A:当组件重新渲染时,React 会根据组件的调用顺序再次按顺序调用对应的 hook。这样,React 可以确保它能够始终访问到正确的状态。例如,当第二次渲染时,React 知道第一个 useState 是哪个状态,因为它在第一次渲染时已经分配了这个状态的索引,这个索引是靠hook调用的顺序产生的索引来追踪的。 所以如果在条件语句、循环或嵌套函数中调用 hook,可能会导致调用顺序的变化,从而产生不可预知的状态。


useImperativeHandle

useImperativeHandle通常是和forwardRef配合使用的,用来把子组件中的属性或者方法暴露给父组件,在进行组件的封装或者组件间的通信的时候常会使用。如下:

// 封装一个可拖拽的组件
const DragComponent = forwardRef((props: {children: React.ReactNode, // 求求你不要挂一个很复杂的组件进来🙏// other config...},ref // ref是必须的) => {// 复位const resetPosition = () => {// todo: 可以在父组件中调用,让这个可拖拽的组件在父组件中回到第一次渲染的位置}useImperativeHandle(ref, () => {resetPosition // 显式声明})return (<div>{props.children}</div>)}
)// 之后在某一个页面中使用它
const Page = () => {const dragRef = useRef(null)const handleOfClick = () => {dragRef.current?.reset();}return (<div><DragComponent ref={dragRef}/><button onClick={handleOfClick}>复位</button></div>)
}

useCallback

useCallBack用来缓存一个函数的引用,它常常配合memo使用以提高渲染的性能。

const Component = memo(({ count, setCount }: { count: number; setCount: () => void }
) => {console.log("CountComponeng render");return (<div><button onClick={() => setCount()}>CountComponeng: {count}</button></div>);})function App() {console.log("App render");const [parentCount, setParentCount] = useState(0);const [childCount, setChildCount] = useState(0);const addChildCount = useCallback(() => {setChildCount(childCount + 1);}, [childCount]);// 这样也行// const addChildCount = useCallback(() => {//     setChildCount((count) => count + 1);// }, []);return (<div id="app"><h1>Hello Vite + React!</h1><button onClick={() => setParentCount(parentCount + 1)}>parentCount: {parentCount}</button><CountComponeng setCount={setChildCount} count={childCount} /></div>);
}export default App;

useReducer

类似redux的更规范的写法,我用的还不多😢,权当记录(该说不说,确实优雅):

import React, { useReducer } from "react";// 定义初始状态
const initialState = { count: 0 };// 定义 reducer 函数
const reducer = (state, action) => {switch (action.type) {case "increment":return { count: state.count + 1 };case "decrement":return { count: state.count - 1 };default:return state;}
};const Counter = () => {// 使用 useReducerconst [state, dispatch] = useReducer(reducer, initialState);return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: "increment" })}>Increment</button><button onClick={() => dispatch({ type: "decrement" })}>Decrement</button></div>);
};
export default Counter;

setState的函数写法和变量写法

我有这样的代码:const [count, setCount] = useState(0),在普通的情况下setCount(count + 1)setCount((count) => count + 1)都能实现count加1并更新视图的操作。

但是,考虑下面这个demo:

const handleOfClick = () => {setCount(count+1)setCount(count+1)setCount(count+1)
}

每一次点击,count最终都只能加1而不能加3,这个React官网介绍的很清楚这里不多说。但是如果把上面的setCount(count+1)换成setCount((count) => count + 1),确实能实现点击一次就+3并更新视图的功能,因为这种函数的写法保证了在进行状态更新时,能够获取到最新的状态值,特别是在状态更新依赖于之前的状态值时,可以避免因为异步执行导致的潜在问题。
始终记住setState是异步的,而且不是没setState一次就更新一次视图的(涉及到React为了优化渲染性能而使用的批量更新策略)。

再考虑一个更普遍的场景:

const Page = () => {const [count, setCount] = useState(1);useEffect(() => {const scrollableContainer = document.getElementById("scrollable-container");scrollableContainer?.addEventListener("scroll", () => {setCount(count + 1)});}, [])return <div id="scroll-container">{count}</div>
}

你会发现,任凭你滚动的再快,count只会加到2,然后就一直不变了。因为此处的useEffect只会执行一次,当你使用 addEventListener 直接绑定事件时,你得到的是一个闭包。在这个闭包中,count 的值是在事件绑定时捕获的(1)
但是把setCount(count+1)换成setCount((count) => count + 1)就能每次滚动的时候都加1,因为它会接受当前状态作为参数,这样每次更新都会基于最新的状态进行计算,从而避免因为闭包问题导致的状态不正确的问题。

http://www.yayakq.cn/news/305411/

相关文章:

  • 如何查看网站服务器无锡上网站建设
  • 学做家常菜的网站南通专业网站排名推广
  • 各大网站图片天津网站建设托管
  • wordpress后台添加底部菜单什么程序做网站容易优化
  • 品牌网站建是啥如何查找昆明做网站服务的公司
  • 纯代码wordpress底部悬浮菜单wordpress优化谷歌
  • 网站被k是怎么回事苏州建设网站制作
  • 建站之星怎么弄相册网站建设公司名称
  • 公司网站建设找谁做企业信息填报年报填写
  • wordpress 显示文章作者wordpress织梦seo
  • 云南网站备案大数据和网站建设
  • h5网站开发工具营销微信管理
  • 厦门哪里有建设网站的国内做任务得数字货币的网站
  • 做电影网站怎么赚钱水果网页设计图片
  • 建站宝盒全能版青岛移动网站建设
  • 保定网站优化排名网站作业成品
  • 上海网站营销推wordpress弹窗
  • 永嘉县住房和城乡建设局网站app快速开发框架
  • 贵阳免费网站建设免费不需要登录的手游
  • 河北建设集团有限公司 信息化网站一个完整的策划案范文
  • 石狮建设局网站打开edge是2345网址导航
  • 客户在我这做的网站被罚做网站 搜索引擎
  • 用js做网站微企推
  • 国内比较好用的建筑案例网站分享经济网站怎么建设
  • 网站建设系统公司做互助盘网站多少钱
  • 深圳市网站建设公广告设计基础教程
  • 企业网站建设的步骤过程wordpress文本编辑器按钮
  • 郑州官网网站推广优化嘿呦一二呦
  • 保定网站排名哪家公司好局网站建设合同
  • html设计网站江门营销网站建设