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

React 思维模式终极指南

React 思维模式终极指南

1. React 核心心智模型

声明式 vs 命令式

// ❌ 命令式:告诉计算机如何做
const container = document.getElementById('container');
const button = document.createElement('button');
button.textContent = 'Click me';
button.addEventListener('click', () => {alert('Button clicked!');
});
container.appendChild(button);// ✅ 声明式:告诉计算机你想要什么
function Button() {const handleClick = () => alert('Button clicked!');return <button onClick={handleClick}>Click me</button>;
}

React 的核心原则

  • UI 是状态的函数UI = f(state)
  • 单向数据流:数据从父组件流向子组件
  • 组件化思维:将 UI 拆分为独立、可复用的部分

2. 组件设计思维

单一职责原则

// ❌ 违反单一职责
function UserProfile({ userId }) {const [user, setUser] = useState(null);const [posts, setPosts] = useState([]);useEffect(() => {// 获取用户信息fetchUser(userId).then(setUser);// 获取用户帖子fetchUserPosts(userId).then(setPosts);}, [userId]);return (<div><h1>{user?.name}</h1><div>{user?.bio}</div><div>{posts.map(post => (<div key={post.id}>{post.title}</div>))}</div></div>);
}// ✅ 单一职责
function UserProfile({ userId }) {return (<div><UserInfo userId={userId} /><UserPosts userId={userId} /></div>);
}function UserInfo({ userId }) {const [user, setUser] = useState(null);useEffect(() => {fetchUser(userId).then(setUser);}, [userId]);return user && (<div><h1>{user.name}</h1><div>{user.bio}</div></div>);
}function UserPosts({ userId }) {const [posts, setPosts] = useState([]);useEffect(() => {fetchUserPosts(userId).then(setPosts);}, [userId]);return (<div>{posts.map(post => (<div key={post.id}>{post.title}</div>))}</div>);
}

组件层次结构设计

// 容器组件 vs 展示组件
function UserListContainer() {const [users, setUsers] = useState([]);const [loading, setLoading] = useState(false);useEffect(() => {setLoading(true);fetchUsers().then(users => {setUsers(users);setLoading(false);});}, []);return <UserList users={users} loading={loading} />;
}// 展示组件 - 只关心如何显示
function UserList({ users, loading }) {if (loading) return <div>Loading...</div>;return (<ul>{users.map(user => (<UserItem key={user.id} user={user} />))}</ul>);
}

3. 状态管理思维

状态提升

// 当多个组件需要共享状态时,将状态提升到最近的共同父组件
function TemperatureConverter() {const [celsius, setCelsius] = useState('');const fahrenheit = celsius !== '' ? (celsius * 9/5 + 32).toFixed(2) : '';return (<div><CelsiusInputvalue={celsius}onChange={setCelsius}/><FahrenheitDisplay value={fahrenheit} /></div>);
}function CelsiusInput({ value, onChange }) {return (<inputtype="number"value={value}onChange={(e) => onChange(e.target.value)}placeholder="Enter Celsius"/>);
}

状态最小化原则

// ❌ 冗余状态
function Form() {const [firstName, setFirstName] = useState('');const [lastName, setLastName] = useState('');const [fullName, setFullName] = useState(''); // 冗余!useEffect(() => {setFullName(`${firstName} ${lastName}`);}, [firstName, lastName]);return <div>{fullName}</div>;
}// ✅ 派生状态
function Form() {const [firstName, setFirstName] = useState('');const [lastName, setLastName] = useState('');const fullName = `${firstName} ${lastName}`; // 派生值return <div>{fullName}</div>;
}

4. 副作用管理思维

useEffect 思维模式

// 思维过程:什么依赖变化时需要重新执行?
function ProductPage({ productId }) {const [product, setProduct] = useState(null);useEffect(() => {// 什么情况下需要重新获取产品信息?// 当 productId 变化时!let cancelled = false;fetchProduct(productId).then(productData => {if (!cancelled) {setProduct(productData);}});// 清理函数:防止已卸载组件的状态更新return () => {cancelled = true;};}, [productId]); // ✅ 正确的依赖数组return product ? <ProductDetails product={product} /> : <Loading />;
}

自定义 Hook 抽象副作用

// 将复杂副作用封装为可复用的 Hook
function useProduct(productId) {const [product, setProduct] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {if (!productId) {setLoading(false);return;}let cancelled = false;setLoading(true);setError(null);fetchProduct(productId).then(productData => {if (!cancelled) {setProduct(productData);setLoading(false);}}).catch(err => {if (!cancelled) {setError(err);setLoading(false);}});return () => {cancelled = true;};}, [productId]);return { product, loading, error };
}// 使用自定义 Hook
function ProductPage({ productId }) {const { product, loading, error } = useProduct(productId);if (loading) return <Loading />;if (error) return <Error message={error.message} />;return <ProductDetails product={product} />;
}

5. 性能优化思维

React.memo 和 useCallback

// ❌ 不必要的重新渲染
function Parent() {const [count, setCount] = useState(0);const [name, setName] = useState('');const handleSubmit = () => {console.log('Submitted:', name);};return (<div><button onClick={() => setCount(c => c + 1)}>Count: {count}</button><Child name={name} onChange={setName} onSubmit={handleSubmit} /></div>);
}// Child 组件在每次 count 变化时都会重新渲染
function Child({ name, onChange, onSubmit }) {console.log('Child rendered'); // 每次都会打印return (<div><input value={name} onChange={e => onChange(e.target.value)} /><button onClick={onSubmit}>Submit</button></div>);
}// ✅ 优化版本
const Child = React.memo(function Child({ name, onChange, onSubmit }) {console.log('Child rendered'); // 只有 name, onChange, onSubmit 变化时才会打印return (<div><input value={name} onChange={e => onChange(e.target.value)} /><button onClick={onSubmit}>Submit</button></div>);
});function Parent() {const [count, setCount] = useState(0);const [name, setName] = useState('');// useCallback 缓存函数引用const handleSubmit = useCallback(() => {console.log('Submitted:', name);}, [name]); // 当 name 变化时重新创建函数return (<div><button onClick={() => setCount(c => c + 1)}>Count: {count}</button><Child name={name} onChange={setName} onSubmit={handleSubmit} /></div>);
}

6. 数据流架构思维

上下文 + 使用Reducer模式

// 复杂状态管理
const AppStateContext = React.createContext();
const AppDispatchContext = React.createContext();function appReducer(state, action) {switch (action.type) {case 'SET_USER':return { ...state, user: action.payload };case 'SET_LOADING':return { ...state, loading: action.payload };case 'ADD_TODO':return { ...state, todos: [...state.todos, action.payload] };default:throw new Error(`Unhandled action type: ${action.type}`);}
}function AppProvider({ children }) {const [state, dispatch] = useReducer(appReducer, {user: null,loading: false,todos: []});return (<AppStateContext.Provider value={state}><AppDispatchContext.Provider value={dispatch}>{children}</AppDispatchContext.Provider></AppStateContext.Provider>);
}// 自定义 Hook 访问状态
function useAppState() {const context = React.useContext(AppStateContext);if (context === undefined) {throw new Error('useAppState must be used within AppProvider');}return context;
}function useAppDispatch() {const context = React.useContext(AppDispatchContext);if (context === undefined) {throw new Error('useAppDispatch must be used within AppProvider');}return context;
}// 在组件中使用
function TodoList() {const { todos } = useAppState();const dispatch = useAppDispatch();const addTodo = (text) => {dispatch({type: 'ADD_TODO',payload: { id: Date.now(), text, completed: false }});};return (<div>{todos.map(todo => (<div key={todo.id}>{todo.text}</div>))}<button onClick={() => addTodo('New todo')}>Add Todo</button></div>);
}

7. 组合优于继承

插槽模式(Slot Pattern)

function Card({ header, children, footer }) {return (<div className="card">{header && <div className="card-header">{header}</div>}<div className="card-body">{children}</div>{footer && <div className="card-footer">{footer}</div>}</div>);
}// 使用
function UserCard({ user }) {return (<Cardheader={<h3>{user.name}</h3>}footer={<button onClick={() => followUser(user.id)}>Follow</button>}><p>{user.bio}</p><p>Followers: {user.followersCount}</p></Card>);
}

渲染属性模式(Render Props)

function DataFetcher({ url, children }) {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {fetch(url).then(res => res.json()).then(setData).catch(setError).finally(() => setLoading(false));}, [url]);return children({ data, loading, error });
}// 使用
function UserProfile({ userId }) {return (<DataFetcher url={`/api/users/${userId}`}>{({ data: user, loading, error }) => {if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error.message}</div>;return (<div><h1>{user.name}</h1><p>{user.email}</p></div>);}}</DataFetcher>);
}

8. 错误边界思维

class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false, error: null };}static getDerivedStateFromError(error) {return { hasError: true, error };}componentDidCatch(error, errorInfo) {console.error('Error caught by boundary:', error, errorInfo);// 可以在这里上报错误到监控服务}render() {if (this.state.hasError) {return this.props.fallback || (<div><h2>Something went wrong.</h2><details>{this.state.error && this.state.error.toString()}</details></div>);}return this.props.children;}
}// 使用
function App() {return (<ErrorBoundary fallback={<div>App crashed!</div>}><UserProfile userId="123" /></ErrorBoundary>);
}

9. 测试思维

// 测试友好的组件设计
function LoginForm({ onSubmit }) {const [email, setEmail] = useState('');const [password, setPassword] = useState('');const handleSubmit = (e) => {e.preventDefault();onSubmit({ email, password });};return (<form onSubmit={handleSubmit}><inputtype="email"value={email}onChange={(e) => setEmail(e.target.value)}placeholder="Email"data-testid="email-input"/><inputtype="password"value={password}onChange={(e) => setPassword(e.target.value)}placeholder="Password"data-testid="password-input"/><button type="submit" data-testid="submit-button">Login</button></form>);
}// 测试示例
describe('LoginForm', () => {it('should call onSubmit with email and password', () => {const mockOnSubmit = jest.fn();render(<LoginForm onSubmit={mockOnSubmit} />);fireEvent.change(screen.getByTestId('email-input'), {target: { value: 'test@example.com' }});fireEvent.change(screen.getByTestId('password-input'), {target: { value: 'password123' }});fireEvent.click(screen.getByTestId('submit-button'));expect(mockOnSubmit).toHaveBeenCalledWith({email: 'test@example.com',password: 'password123'});});
});

10. 进阶思维模式

不可变更新模式

// 使用 Immer 简化不可变更新
import produce from 'immer';function TodoApp() {const [todos, setTodos] = useState([]);const addTodo = (text) => {setTodos(produce(draft => {draft.push({ id: Date.now(), text, completed: false });}));};const toggleTodo = (id) => {setTodos(produce(draft => {const todo = draft.find(t => t.id === id);if (todo) todo.completed = !todo.completed;}));};
}

依赖注入思维

// 创建服务上下文
const ApiServiceContext = React.createContext();function ApiServiceProvider({ children, service }) {return (<ApiServiceContext.Provider value={service}>{children}</ApiServiceContext.Provider>);
}// 在组件中注入依赖
function UserProfile({ userId }) {const apiService = useContext(ApiServiceContext);const [user, setUser] = useState(null);useEffect(() => {apiService.getUser(userId).then(setUser);}, [apiService, userId]);return <div>{user?.name}</div>;
}// 测试时可以轻松替换实现
const mockApiService = {getUser: jest.fn().mockResolvedValue({ name: 'Test User' })
};render(<ApiServiceProvider service={mockApiService}><UserProfile userId="123" /></ApiServiceProvider>
);

总结

React 思维模式的核心是:

  1. 声明式思维:描述 UI 应该是什么样子,而不是如何操作 DOM
  2. 组件化思维:将复杂 UI 拆分为独立、可复用的组件
  3. 不可变思维:状态更新应该创建新对象,而不是修改现有对象
  4. 单向数据流:数据从父组件流向子组件,事件从子组件流向父组件
  5. 组合思维:通过组件组合而非继承来构建复杂 UI
  6. 副作用管理:明确副作用依赖,合理使用 useEffect
  7. 性能意识:理解重新渲染的触发条件,合理使用优化手段

掌握这些思维模式,你将能够编写出更清晰、可维护、高性能的 React 代码。

http://www.dtcms.com/a/499853.html

相关文章:

  • 网站开发环境构建手机上可以做网站
  • 江苏住房与城乡建设部网站番禺人才网招聘网官网
  • 高并发内存池项目开发记录 - 02
  • FACT-AUDIT
  • 怎么做网站镜像三种常见的网络营销方式
  • 登陆工伤保险网站 提示未授权 怎么做wordpress如何导出
  • 做外贸网站怎么做人才网网站开发手册
  • 软件测试之压力测试详解
  • vue3二次封装element-plus表格,slot透传,动态slot。
  • RDP 远程桌面连接常见问题详解:仅使用网络级别身份验证、微软账户密码、远程登录后的用户状态
  • C程序中的循环语句
  • 湖南省城乡建设厅网站邮箱网站怎么做
  • Linux基础指令(完结)、shell命令与Linux权限(1) |tar|bc|uname|热键|shutdown|shell|权限
  • 能看网站的浏览器wordpress 自定义注册表单
  • 佛山网页网站设计做网站要多少人
  • DeepSeek辅助利用搬移底层xml实现快速编辑xlsx文件的python程序
  • 营销型外贸网站建设医疗网站怎么做seo
  • 【Swift】LeetCode 3. 无重复的最长子串
  • 深圳品牌网站建设公司招聘百度账号中心官网
  • jdk.nio.zipfs 包详解
  • 小说网站建设目的车牌照损坏在网站做的能用吗
  • 专业提供网站建设服务包括wordpress 联系人表单
  • Spring 核心原理:Bean 作用域、生命周期与 SpringBoot 自动配置
  • [MLflow] 环境管理 | MLflow模型 | Flavors与pyfunc
  • iis网站防盗链浙江鼎兴建设有限公司网站
  • python+django/flask的在线心理咨询系统
  • 继电保护:距离保护:过渡电阻影响
  • FAST DDS-GEN--通过 IDL 定义数据类型
  • 网站建设推广信息企业网站 建设流程
  • 连云港建设局网站网站建设培训南宁