前端状态管理:别让你的状态变成一团乱麻

前端状态管理:别让你的状态变成一团乱麻

毒舌时刻

这状态管理得跟蜘蛛网似的,谁能理得清?

各位前端同行,咱们今天聊聊前端状态管理。别告诉我你还在使用 setState 管理所有状态,那感觉就像在没有地图的情况下寻宝——能找,但累死你。

为什么你需要状态管理

最近看到一个项目,组件之间传递状态需要经过 5 层,修改一个状态要修改多个地方。我就想问:你是在做状态管理还是在做传递游戏?

反面教材

// 反面教材:混乱的状态管理 function App() { const [user, setUser] = useState(null); const [posts, setPosts] = useState([]); const [comments, setComments] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchData() { setLoading(true); try { const userResponse = await fetch('/api/user'); const userData = await userResponse.json(); setUser(userData); const postsResponse = await fetch('/api/posts'); const postsData = await postsResponse.json(); setPosts(postsData); const commentsResponse = await fetch('/api/comments'); const commentsData = await commentsResponse.json(); setComments(commentsData); } catch (error) { console.error('Error fetching data:', error); } finally { setLoading(false); } } fetchData(); }, []); return ( <div> {loading ? <div>加载中...</div> : ( <div> <UserHeader user={user} /> <PostList posts={posts} comments={comments} /> </div> )} </div> ); } function UserHeader({ user }) { return <h1>Welcome, {user?.name}</h1>; } function PostList({ posts, comments }) { return ( <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> <CommentList postId={post.id} comments={comments} /> </div> ))} </div> ); } function CommentList({ postId, comments }) { const postComments = comments.filter(comment => comment.postId === postId); return ( <div> {postComments.map(comment => ( <div key={comment.id}>{comment.content}</div> ))} </div> ); } 

毒舌点评:这状态管理,就像在玩传球游戏,球传来传去都不知道传到哪里了。

正确姿势

1. Redux Toolkit

// 正确姿势:Redux Toolkit // 1. 安装依赖 // npm install @reduxjs/toolkit react-redux // 2. 创建 store // store/index.js import { configureStore } from '@reduxjs/toolkit'; import userReducer from './slices/userSlice'; import postsReducer from './slices/postsSlice'; import commentsReducer from './slices/commentsSlice'; export const store = configureStore({ reducer: { user: userReducer, posts: postsReducer, comments: commentsReducer, }, }); // 3. 创建 slices // store/slices/userSlice.js import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; export const fetchUser = createAsyncThunk('user/fetchUser', async () => { const response = await fetch('/api/user'); return response.json(); }); const userSlice = createSlice({ name: 'user', initialState: { data: null, loading: false, error: null, }, reducers: {}, extraReducers: (builder) => { builder .addCase(fetchUser.pending, (state) => { state.loading = true; state.error = null; }) .addCase(fetchUser.fulfilled, (state, action) => { state.loading = false; state.data = action.payload; }) .addCase(fetchUser.rejected, (state, action) => { state.loading = false; state.error = action.error.message; }); }, }); export default userSlice.reducer; // 4. 使用 store // index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { Provider } from 'react-redux'; import { store } from './store'; ReactDOM.createRoot(document.getElementById('root')).render( <Provider store={store}> <App /> </Provider> ); // 5. 使用状态 // App.jsx import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchUser } from './store/slices/userSlice'; import { fetchPosts } from './store/slices/postsSlice'; import { fetchComments } from './store/slices/commentsSlice'; import UserHeader from './components/UserHeader'; import PostList from './components/PostList'; function App() { const dispatch = useDispatch(); const { loading } = useSelector((state) => state.user); useEffect(() => { dispatch(fetchUser()); dispatch(fetchPosts()); dispatch(fetchComments()); }, [dispatch]); return ( <div> {loading ? <div>加载中...</div> : ( <div> <UserHeader /> <PostList /> </div> )} </div> ); } // components/UserHeader.jsx import React from 'react'; import { useSelector } from 'react-redux'; function UserHeader() { const user = useSelector((state) => state.user.data); return <h1>Welcome, {user?.name}</h1>; } export default UserHeader; // components/PostList.jsx import React from 'react'; import { useSelector } from 'react-redux'; import CommentList from './CommentList'; function PostList() { const posts = useSelector((state) => state.posts.data); return ( <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> <CommentList postId={post.id} /> </div> ))} </div> ); } export default PostList; // components/CommentList.jsx import React from 'react'; import { useSelector } from 'react-redux'; function CommentList({ postId }) { const comments = useSelector((state) => state.comments.data.filter(comment => comment.postId === postId) ); return ( <div> {comments.map(comment => ( <div key={comment.id}>{comment.content}</div> ))} </div> ); } export default CommentList; 

2. Zustand

// 正确姿势:Zustand // 1. 安装依赖 // npm install zustand // 2. 创建 store // store/index.js import { create } from 'zustand'; import { persist } from 'zustand/middleware'; const useStore = create( persist( (set, get) => ({ user: null, posts: [], comments: [], loading: false, error: null, fetchUser: async () => { set({ loading: true, error: null }); try { const response = await fetch('/api/user'); const data = await response.json(); set({ user: data, loading: false }); } catch (error) { set({ error: error.message, loading: false }); } }, fetchPosts: async () => { set({ loading: true, error: null }); try { const response = await fetch('/api/posts'); const data = await response.json(); set({ posts: data, loading: false }); } catch (error) { set({ error: error.message, loading: false }); } }, fetchComments: async () => { set({ loading: true, error: null }); try { const response = await fetch('/api/comments'); const data = await response.json(); set({ comments: data, loading: false }); } catch (error) { set({ error: error.message, loading: false }); } }, }), { name: 'app-storage', } ) ); export default useStore; // 3. 使用 store // App.jsx import React, { useEffect } from 'react'; import useStore from './store'; import UserHeader from './components/UserHeader'; import PostList from './components/PostList'; function App() { const { loading, fetchUser, fetchPosts, fetchComments } = useStore(); useEffect(() => { fetchUser(); fetchPosts(); fetchComments(); }, [fetchUser, fetchPosts, fetchComments]); return ( <div> {loading ? <div>加载中...</div> : ( <div> <UserHeader /> <PostList /> </div> )} </div> ); } // components/UserHeader.jsx import React from 'react'; import useStore from '../store'; function UserHeader() { const user = useStore((state) => state.user); return <h1>Welcome, {user?.name}</h1>; } export default UserHeader; // components/PostList.jsx import React from 'react'; import useStore from '../store'; import CommentList from './CommentList'; function PostList() { const posts = useStore((state) => state.posts); return ( <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> <CommentList postId={post.id} /> </div> ))} </div> ); } export default PostList; // components/CommentList.jsx import React from 'react'; import useStore from '../store'; function CommentList({ postId }) { const comments = useStore((state) => state.comments.filter(comment => comment.postId === postId) ); return ( <div> {comments.map(comment => ( <div key={comment.id}>{comment.content}</div> ))} </div> ); } export default CommentList; 

3. Jotai

// 正确姿势:Jotai // 1. 安装依赖 // npm install jotai // 2. 创建 atoms // store/atoms.js import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'; import { atomWithStorage } from 'jotai/utils'; // 状态 atoms const userAtom = atomWithStorage('user', null); const postsAtom = atomWithStorage('posts', []); const commentsAtom = atomWithStorage('comments', []); const loadingAtom = atom(false); const errorAtom = atom(null); // 动作 atoms const fetchUserAtom = atom( null, async (_, set) => { set(loadingAtom, true); set(errorAtom, null); try { const response = await fetch('/api/user'); const data = await response.json(); set(userAtom, data); } catch (error) { set(errorAtom, error.message); } finally { set(loadingAtom, false); } } ); const fetchPostsAtom = atom( null, async (_, set) => { set(loadingAtom, true); set(errorAtom, null); try { const response = await fetch('/api/posts'); const data = await response.json(); set(postsAtom, data); } catch (error) { set(errorAtom, error.message); } finally { set(loadingAtom, false); } } ); const fetchCommentsAtom = atom( null, async (_, set) => { set(loadingAtom, true); set(errorAtom, null); try { const response = await fetch('/api/comments'); const data = await response.json(); set(commentsAtom, data); } catch (error) { set(errorAtom, error.message); } finally { set(loadingAtom, false); } } ); export { userAtom, postsAtom, commentsAtom, loadingAtom, errorAtom, fetchUserAtom, fetchPostsAtom, fetchCommentsAtom }; // 3. 使用 atoms // App.jsx import React, { useEffect } from 'react'; import { useAtomValue, useSetAtom } from 'jotai'; import { loadingAtom, fetchUserAtom, fetchPostsAtom, fetchCommentsAtom } from './store/atoms'; import UserHeader from './components/UserHeader'; import PostList from './components/PostList'; function App() { const loading = useAtomValue(loadingAtom); const fetchUser = useSetAtom(fetchUserAtom); const fetchPosts = useSetAtom(fetchPostsAtom); const fetchComments = useSetAtom(fetchCommentsAtom); useEffect(() => { fetchUser(); fetchPosts(); fetchComments(); }, [fetchUser, fetchPosts, fetchComments]); return ( <div> {loading ? <div>加载中...</div> : ( <div> <UserHeader /> <PostList /> </div> )} </div> ); } // components/UserHeader.jsx import React from 'react'; import { useAtomValue } from 'jotai'; import { userAtom } from '../store/atoms'; function UserHeader() { const user = useAtomValue(userAtom); return <h1>Welcome, {user?.name}</h1>; } export default UserHeader; // components/PostList.jsx import React from 'react'; import { useAtomValue } from 'jotai'; import { postsAtom } from '../store/atoms'; import CommentList from './CommentList'; function PostList() { const posts = useAtomValue(postsAtom); return ( <div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> <CommentList postId={post.id} /> </div> ))} </div> ); } export default PostList; // components/CommentList.jsx import React from 'react'; import { useAtomValue } from 'jotai'; import { commentsAtom } from '../store/atoms'; function CommentList({ postId }) { const comments = useAtomValue(commentsAtom); const postComments = comments.filter(comment => comment.postId === postId); return ( <div> {postComments.map(comment => ( <div key={comment.id}>{comment.content}</div> ))} </div> ); } export default CommentList; 

毒舌点评:这才叫前端状态管理,集中管理状态,组件之间共享状态,再也不用担心状态传递的问题了。

Read more

【AIGC】ChatGPT 结构化 Prompt 的高级应用

【AIGC】ChatGPT 结构化 Prompt 的高级应用

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]本文专栏: AIGC |ChatGPT 文章目录 * 💯前言 * 💯标识符的使用(Use of Identifiers) * 1. `#` * 2. `<>` * 3. `-` 或 `·` * 4. `[]` * 💯属性词的重要性和应用 * 应用场景 * 💯具体模块的结构化应用 * Role(角色) * Profile(简介) * Background(背景) * Goals(目标) * Constraints(约束条件) * Skills(技能) * Initialization(初始化) * 工作流程 * 💯小结 💯前言 随着人工智能生成内容(AIGC)技术的发展,如何更高效地与智能模型进行互动,成为提升任务执行效率和信息处理能力的关键环节。而结构化 Prompt的应用,作为智能对话与任务指令设计中的核心方法,为用户提供了强大的工具,使得信息表达更加清晰、

【AIGC】Claude Code 模型配置详解

模型配置解释 一、核心参数含义与作用 这些参数本质是 Anthropic Claude 模型在代码开发场景下的预设标识符,用于简化不同Claude模型版本的调用配置(避免硬编码模型ID),每个参数对应不同定位的Claude模型,具体如下: 参数名核心作用适用场景对应官方模型ID示例ANTHROPIC_MODEL通用/顶层模型参数,可覆盖其他默认模型参数,是所有Claude调用的“全局开关”统一指定所有代码任务的模型(如全局切换为Sonnet)可设为任意Claude模型ID(如claude-3-5-sonnet-20240620)ANTHROPIC_DEFAULT_OPUS_MODEL预设Claude Opus(旗舰版)模型的标识符,Opus是推理能力最强的模型复杂代码任务(大型项目重构、算法设计、多语言代码整合、核心逻辑开发)claude-3-5-opus-20240620(最新Opus 3.5)、claude-3-opus-20240229ANTHROPIC_DEFAULT_SONNET_MODEL预设Claude Sonnet(平衡版)模型的标识符,性能/速度/成本最优平

从 0 到 1:解决 VsCode 远程连服务器后 Github Copilot 无法使用问题

从 0 到 1:解决 VS Code 远程连服务器后 GitHub Copilot 无法使用问题 当您使用 VS Code 的远程功能(如 SSH 或容器)连接到服务器时,GitHub Copilot 可能无法正常工作,这通常是由于远程环境中的网络、扩展安装或身份验证问题导致的。我将一步步引导您解决这个问题,确保过程清晰可靠。请按照顺序操作,并测试每个步骤。 步骤 1: 确认本地 Copilot 正常工作 在开始远程连接前,先确保 Copilot 在您的本地 VS Code 中工作正常。 * 打开本地 VS Code。 * 创建一个新文件(如 test.py),输入一些代码(如 def

2026年高校AIGC检测新规解读:AI率多少算合格?

2026年高校AIGC检测新规解读:AI率多少算合格?

2026年高校AIGC检测新规解读:AI率多少算合格? 从2024年知网正式上线AIGC检测功能开始,短短两年时间,"AI率"已经从一个新鲜名词变成了每个毕业生必须面对的硬性指标。2026年,各高校的AIGC检测政策进一步收紧和细化,要求也越来越明确。 那么,2026年AI率到底多少才算合格?不同学校的标准差别大吗?不合格会面临什么后果?本文将对这些问题进行深入解读。 一、AIGC检测已成为毕业论文审查的标配 回顾AIGC检测在高校中的普及历程,可以用"指数级扩散"来形容: * 2024年:知网上线AIGC检测功能,少数985/211院校开始试点,大部分学校处于观望状态 * 2025年:超过60%的本科院校和80%的研究生培养单位将AIGC检测纳入论文审查流程 * 2026年:AIGC检测基本实现全覆盖,包括专科院校在内的绝大部分高等教育机构都已建立相关制度 这一进程的背后,是教育部在2025年初发布的《关于加强高等学校学位论文学术诚信管理的指导意见》,其中明确提到"鼓励各高校引入人工智能生成内容检测机制,将AIGC检测作为论文质量保障的重要环节"。 虽然教育部没