Evan:Vibe Coding提效秘籍,一口气学会95% React前端开发
Evan:Vibe Coding提效秘籍,一口气学会95% React前端开发
Evan:Vibe Coding提效秘籍,一口气学会95% React前端开发 Evan:Vibe Coding提效秘籍,一口气学会95% React前端开发 Modified August 30, 2025 Code block Plain Text Copy value={email} onChange={(e) = setEmail(e.target.value)} / {/ 因为handleSubmit每次都是新的,被React.memo优化的SubmitButton 会认为props发生了变化,从而在每一次按键时都进行不必要的重渲染。 /} <SubmitButton onSubmit={handleSubmit} / </form ); } // const SubmitButton = React.memo(({ onSubmit }) = { ... }); 正确的做法是,我们拥抱受控组件带来的高频重渲染,但使用useCallback和useMemo 精准地“隔离”其影响,切断不必要的渲染链条,只让必须更新的部分更新。 useCallback和useMemo的底层都基于一个经典的编程概念:记忆化 (Memoization)。 当我们第一次调用时,React执行函数,然后把结果(一个函数实例或一个值)连同我们提供的依赖数组一起“存”起来。 在后续的重渲染中,React不会立即重新计算,而是会逐个比较这次传入的依赖数组中的每一项,和上次存起来的是否完全一样。 如果完全一样:React会跳过所有计算,直接从缓存里返回结果。 如果任何一项不同:React会认为“输入变了,结果可能也需要更新”,于是它会重新执行计算,并将这个新结果存入缓存,以备下次比较。 Code block Plain Text Copy // ✅ 精准控制:让受控组件的重渲染“指哪打哪” function ContactForm() { const [email, setEmail] = useState(''); // ✅ 使用useCallback,我们告诉React:“请记住这个handleSubmit函数”。 // 只要依赖项数组[]不变,无论ContactForm重渲染多少次, // handleSubmit的函数引用都将保持稳定。 const handleSubmit = useCallback(() = { alert(Submitting ${email}); }, [email]); // 依赖项是email,这样在提交时总能获取到最新的email值 return ( <form <input type="email" value={email} onChange={(e) = setEmail(e.target.value)} / {/ 现在,即使用户不停输入导致ContactForm频繁重渲染, 传递给SubmitButton的onSubmit prop始终是同一个。 SubmitButton的memo优化生效,不再进行无效的渲染。 /} <SubmitButton onSubmit={handleSubmit} / </form ); } useCallback 和useMemo都是用于记忆,区别在于useCallback是记忆化函数本身。而useMemo是记忆化函数的返回值。 7. Context API 跨越组件的“任意门” 🌐 当多个深层嵌套的组件需要共享同一个状态(如主题、用户信息)时,为了避免通过props逐层传递,我们可以使用Context API。 想象一下,顶层组件有一个theme状态,深层组件需要根据它改变样式。如果层层传递props,代码会非常繁琐。 Code block Plain Text Copy // ❌ BAD: Prop drilling nightmare passing props through every level function App() { const [theme, setTheme] = useState('light'); return ( <Header theme={theme} setTheme={setTheme} / <Main theme={theme} setTheme={setTheme} / <Footer theme={theme} setTheme={setTheme} / ); } function Header({ theme, setTheme }) { return <Nav theme={theme} setTheme={setTheme} / ; } function Nav({ theme, setTheme }) { return <ThemeButton theme={theme} onClick={setTheme} / ; } 正确的做法是使用Context。在顶层用Provider提供状态,在任何子组件中用useContext直接消费状态。 Code block Plain Text Copy // ✅ GOOD: Context API eliminates prop drilling // 🐍 Python: Like a global variable, but better managed // Note: The actual implementation is now in src/contexts/ThemeContext.tsx for better organization functionThemeToggle() { // Using the custom hook from our contexts folder const { theme, toggleTheme } = useTheme(); return ( <div className="widget" <h3 <span className="widget icon" 🎨</span Theme Switcher <span className="pattern badge" Context API</span </h3 <p className="text sm mb 4" style={{ color: 'var( muted foreground)' }} Global state without prop drilling </p <div className="text center" <div className="text xl mb 4" Current theme: <strong {theme}</strong </div <Button onClick={toggleTheme} Switch to {theme === 'light' ? '🌙 Dark' : '☀️ Light'} mode </Button </div </div ); } 8. Custom Hooks 封装逻辑的“魔法书” 📚 我们之前提到的useState,useEffect等待都是Hook。 当多个组件需要用到同一套复杂的状态逻辑时(如操作localStorage、订阅窗口大小),我们也可以将这套逻辑封装成一个自定义Hook。 一个 Hook 本质上是一个 JavaScript 函数,但它必须遵守两条规则,以便与 React 世界互动: 1.名称必须以use 开头。者使得 React Linter 可以识别一个函数是否为 Hook 。 例如,useLocalStorage是一个合法的 Hook 名,而getLocalStorage 则不是。 2.只能在顶层调用 Hooks。不能在循环、条件判断或嵌套函数中调用 Hook。这是因为 React 依赖于 Hooks在每次渲染中都以完全相同的顺序被调用。 React 内部没有为每个 Hook 命名,它就像一个“钩子列表”,通过这个稳定的调用顺序,来确保useState 等 Hook 能在多次渲染之间正确地关联到同一个组件的同一个状态。 以操作localStorage为例,我们可以创建一个useLocalStorage的自定义Hook,它内部封装了useState和useEffect来处理数据的读取和写入。 Code block Plain Text Copy // 自定义Hook:封装所有与localStorage交互的逻辑 function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() = { // ... 读取localStorage的逻辑 }); const setValue = (value) = { // ... 写入localStorage的逻辑 setStoredValue(value); }; return [storedValue, setValue]; } 这样,任何组件都可以通过一行代码来使用这个封装好的逻辑,使组件本身的代码更简洁、更关注于UI。 Code block Plain Text Copy // ✅ 在任何组件中轻松使用 function NotesWidget() { // 一行代码,就拥有了与localStorage同步的状态 const [notes, setNotes] = useLocalStorage('my notes', []); // ... UI渲染 } 本文部分内容参考并改编自 Sean 的视频 《You Can Learn 95% React/Typescript Like A Pro. NO STUCK IN VIBE CODING | State, Hooks, Context, Memo》。 该视频详细讲解了React和TypeScript的核心概念, 包括useState([09:22])、useEffect([12:02])、Props([21:38])、条件渲染([30:03])、列表渲染([30:12])、事件处理([37:56])、Context([44:20])以及自定义Hooks([52:50])等。 推荐大家观看原视频以获得更深入的理解。 如果需要完整实例代码,请关注公众号「星空拾荒」,在后台发送 React 领取。 以上, 既然看到这里了,如果觉得不错,随手点个赞、推荐、转发三连吧,你的支持是我持续创作的动力。我们下期见。 为了帮助大家减少AI信息差,我拉了个AI交流群,围绕着AI前沿、AI编程、AI工作流、AI Agent等进行讨论。 感兴趣的可以关注公众号「星空拾荒」,后台回复「AI交流群」 正确的做法是,我们拥抱受控组件带来的高频重渲染,但使用useCallback和useMemo 精准地“隔离”其影响,切断不必要的渲染链条,只让必须更新的部分更新。 useCallback和useMemo的底层都基于一个经典的编程概念:记忆化 (Memoization)。 当我们第一次调用时,React执行函数,然后把结果(一个函数实例或一个值)连同我们提供的依赖数组一起“存”起来。 在后续的重渲染中,React不会立即重新计算,而是会逐个比较这次传入的依赖数组中的每一项,和上次存起来的是否完全一样。 如果完全一样:React会跳过所有计算,直接从缓存里返回结果。 如果任何一项不同:React会认为“输入变了,结果可能也需要更新”,于是它会重新执行计算,并将这个新结果存入缓存,以备下次比较。 useCallback 和useMemo都是用于记忆,区别在于useCallback是记忆化函数本身。而useMemo是记忆化函数的返回值。 7. Context API 跨越组件的“任意门” 🌐 当多个深层嵌套的组件需要共享同一个状态(如主题、用户信息)时,为了避免通过props逐层传递,我们可以使用Context API。 想象一下,顶层组件有一个theme状态,深层组件需要根据它改变样式。如果层层传递props,代码会非常繁琐。 正确的做法是使用Context。在顶层用Provider提供状态,在任何子组件中用useContext直接消费状态。 8. Custom Hooks 封装逻辑的“魔法书” 📚 我们之前提到的useState,useEffect等待都是Hook。 当多个组件需要用到同一套复杂的状态逻辑时(如操作localStorage、订阅窗口大小),我们也可以将这套逻辑封装成一个自定义Hook。 一个 Hook 本质上是一个 JavaScript 函数,但它必须遵守两条规则,以便与 React 世界互动: 1.名称必须以use 开头。者使得 React Linter 可以识别一个函数是否为 Hook 。 例如,useLocalStorage是一个合法的 Hook 名,而getLocalStorage 则不是。 2.只能在顶层调用 Hooks。不能在循环、条件判断或嵌套函数中调用 Hook。这是因为 React 依赖于 Hooks在每次渲染中都以完全相同的顺序被调用。 React 内部没有为每个 Hook 命名,它就像一个“钩子列表”,通过这个稳定的调用顺序,来确保useState 等 Hook 能在多次渲染之间正确地关联到同一个组件的同一个状态。 以操作localStorage为例,我们可以创建一个useLocalStorage的自定义Hook,它内部封装了useState和useEffect来处理数据的读取和写入。 这样,任何组件都可以通过一行代码来使用这个封装好的逻辑,使组件本身的代码更简洁、更关注于UI。 本文部分内容参考并改编自 Sean 的视频 《You Can Learn 95% React/Typescript Like A Pro. NO STUCK IN VIBE CODING | State, Hooks, Context, Memo》。 该视频详细讲解了React和TypeScript的核心概念, 包括useState([09:22])、useEffect([12:02])、Props([21:38])、条件渲染([30:03])、列表渲染([30:12])、事件处理([37:56])、Context([44:20])以及自定义Hooks([52:50])等。 推荐大家观看原视频以获得更深入的理解。 如果需要完整实例代码,请关注公众号「星空拾荒」,在后台发送 React 领取。 以上, 既然看到这里了,如果觉得不错,随手点个赞、推荐、转发三连吧,你的支持是我持续创作的动力。我们下期见。 为了帮助大家减少AI信息差,我拉了个AI交流群,围绕着AI前沿、AI编程、AI工作流、AI Agent等进行讨论。 感兴趣的可以关注公众号「星空拾荒」,后台回复「AI交流群」 如果喜欢我的文章,欢迎关注我的公众号或者添加我的微信,进一步交流~ 公众号 公众号 公众号 原文链接🔗:https://mp.weixin.qq.com/s/1aYoEMMDPB8S0QTFQCcajw 原创 喜欢萨摩耶的Evan 星空拾荒 2025年08月30日 18:26 广东 原文链接🔗:https://mp.weixin.qq.com/s/1aYoEMMDPB8S0QTFQCcajw 原创 喜欢萨摩耶的Evan 星空拾荒 2025年08月30日 18:26 广东 随着Vibe Coding风靡全球,哪怕不是计算机出身的人,也可以在AI的帮助下创造属于自己的工具和产品。 面对一个新Idea,熟练地打开Cursor()或Cl 随着Vibe Coding风靡全球,哪怕不是计算机出身的人,也可以在AI的帮助下创造属于自己的工具和产品。 面对一个新Idea,熟练地打开Cursor或Claude Code,向AI下达指令,几分钟后一个可运行的demo就完成了。 但当我们想要增加新的功能,或者想把产品向生产级别过渡的时候,噩梦出现了。 任何一个小bug的出现,都可能需要跟AI花费大半小时沟通才能解决,解决的过程可能把我们测试完成的功能改坏掉。 这就是Vibe Coding正在面临的困境:我们善用工具,却被工具绑架。 而这一切的根源,都是我们对原理的陌生。 在AI时代,我们不需要了解语法和框架的细节,但是我们至少需要了解最宏观和High Level的原理,才能让我们更好地指挥AI完成我们的需求。 今天,我们将用最直接的案例,剖析 React 中最高频的8个核心场景。 掌握它们,就等于覆盖了95%的日常开发需求,让你能真正看懂 AI 生成的代码,与它高效协作,成为一名合格的“AI指挥官”。 目录 1. useState 状态管理的心脏 2. useEffect 副作用的“隔离区” 3. Props & Component Composition 组件的复用哲学 4. Conditional Rendering 状态驱动的UI 5. List Rendering & Keys 高效显示动态数据 6. Event Handling & Forms 用户交互的艺术 7. Context API 跨越组件的“任意门” 8. Custom Hooks 封装逻辑的“魔法书” 1. useState 状态管理的心脏 🔢 当我们定义变量,并且希望每一次变量的改变都会被实时渲染的时候,我们就需要用到useState。 拿计数器作为例子,我们希望每点击一次+号,计数器的数字就会加一,点击 号会减一。 如果我们使用普通的变量定义,我们会发现无论点击多少次加号,浏览器显示的数字都不会改变。 这是因为变量虽然改变了,但是并没有被渲染。 正确的方法应该是使用useState, const [count, setCount] = useState(0); 其中count是变量名称,setCount是修改变量的函数,0是赋给变量的初值。 2. useEffect 副作用的“隔离区” ⏰ 当我们需要处理API请求、定时器或直接操作DOM等“副作用”时,就需要useEffect。 所谓副作用,就是指组件除了计算和返回UI之外,执行的任何其他操作。 以实时时钟为例,我们希望每秒更新一次时间。 如果直接在组件里写setTimeout,会导致无限循环,因为每次状态更新都会触发重新渲染,从而再次执行setTimeout。 正确的方法是将副作用逻辑放入useEffect中。useEffect可以精确控制代码的执行时机,并提供一个清理函数来避免内存泄漏。 放在useEffect中的逻辑,只会在我们指定的依赖项发生变化时才会重新执行(如果依赖项数组为空,则只在组件首次挂载时执行一次), 从而避免了在每次渲染时都运行导致的无限循环问题。 3. Props & Component Composition 组件的复用哲学 🎨 当我们希望一个组件能在不同场景下被复用时,就需要使用props。 当我们需要创建不同样式的按钮,比如“提交”、“取消”等。 如果为每种按钮都创建一个新组件,代码会变得冗余且难以维护。 正确的方法是创建一个通用的Button组件,通过props来接收不同的配置(如样式、文字内容、点击事件),从而实现复用。 我们可以将React组件看作一个JavaScript函数。 而props就相当于传递给这个函数的参数。它是一个普通的对象,父组件通过类似HTML属性的语法,将数据“喂”给子组件。 这个数据流是单向的,即从父组件流向子组件。 一个极其重要的原则是:子组件永远不应该修改自己接收到的 props。props对于子组件来说是只读的。 这保证了应用的稳定性和数据的可预测性——我们总能追溯到状态的源头(父组件)。 props中还有一个特殊的成员叫做children,它代表了组件标签内部嵌套的所有内容。 比如在使用<Button 点我</Button 时,字符串"点我"就会作为props.children被传递给Button组件。 理解了这些原理后,我们再来看如何创建一个通用的Button组件。 正确的方法是通过props来接收不同的配置(如样式variant、文字内容children、点击事件onClick等),从而实现最大程度的复用。 4. Conditional Rendering 状态驱动的UI 👤 当我们需要根据不同的应用状态(如加载中、加载成功、加载失败)显示不同的UI时,就需要条件渲染。 以加载用户信息为例,糟糕的设计是把所有可能的UI元素都堆在一起,让用户感到困惑。 正确的做法是根据当前的状态(loading, error, user),精确地只显示与该状态对应的UI。 我们利用 JavaScript 的原生逻辑操作符(如三元运算符? :或者逻辑与&&)来实现条件渲染。当state 改变时,React 会重新执行渲染函数,计算出新的UI 声明。 5. List Rendering & Keys 高效显示动态数据 📝 当我们需要渲染一个项目列表时,必须为每个列表项提供一个稳定且唯一的key。 以待办事项列表为例,如果使用数组的索引index作为key,当列表项被删除或重新排序时,React可能会混淆它们,导致不必要的重新渲染和潜在的bug。 正确的做法是使用数据项中自带的、独一无二的ID(如todo.id)作为key。 这能帮助React精确地识别每个元素,从而高效地更新UI。 6. useCallback & useMemo 用户交互的艺术 📧 在React中,当我们需要处理用户的输入时,最佳实践是“受控组件”。 也就是表单元素(如<input )的值不再由DOM自己管理,而是完全由React的state来控制。 这创造了一个清晰、可预测的单向数据流闭环:state驱动input的value 用户输入触发onChange onChange调用setState更新state state 变化触发UI重新渲染。 但这种模式有一个与生俱来的缺陷:用户的每一次按键(onChange)都会调用setState,从而导致拥有这个state的整个组件重新渲染。 当表单变得复杂,或者包含多个子组件时,这种高频的重渲染就会成为性能瓶颈。