您现在的位置是:首页 > 文章详情

React 进阶优化概念(6 个)——从能写组件到写好组件(下)| 葡萄城技术团队

日期:2025-09-25点击:45

React 进阶优化概念(6 个)——从能写组件到写好组件(下)

前言:为什么需要进阶概念?

国内开发者在 React 项目迭代中,常会遇到两个问题:

  1. “性能瓶颈”:比如列表渲染卡顿、组件反复重渲染;
  2. “复杂状态难管理”:比如购物车多商品操作、表单多字段联动。

这篇整理的 6 个进阶概念,就是解决这些问题的“钥匙”:从useRef操作 DOM,到useMemo/useCallback优化性能,再到自定义 Hooks 复用逻辑,每个都针对国内项目高频痛点,帮你从“能写组件”升级到“写好组件”。

1. React 中 useRef 的使用:不止是 DOM 操作

核心作用

useRef返回一个“持久化的 ref 对象”,它有两个核心用途:

  1. 操作 DOM:获取 DOM 元素的引用(如获取输入框焦点、读取元素尺寸);
  2. 保存持久化数据:数据更新时不会触发组件重渲染(如保存定时器 ID、上一次的状态值)。

国内开发中,useRef常用来解决“无法获取最新状态”的问题(比如定时器中访问过时的 state),或实现“输入框自动聚焦”(表单场景高频需求)。

国内项目示例:DOM 操作+持久化数据(双场景实战)

import React, { useState, useRef, useEffect } from 'react';
import { Input, Button, message } from 'antd';

const UseRefDemo = () => {
  const [count, setCount] = useState(0);
  // 1. 用途1:操作DOM——获取输入框引用
  const inputRef = useRef(null);
  // 2. 用途2:保存持久化数据——定时器ID(更新不触发重渲染)
  const timerRef = useRef(null);

  // 示例1:输入框自动聚焦(页面加载后、点击按钮时)
  useEffect(() => {
    // 页面加载后,让输入框聚焦(国内表单常见需求)
    inputRef.current.focus();
  }, []);

  const handleFocusInput = () => {
    // 点击按钮,让输入框聚焦
    inputRef.current.focus();
  };

  // 示例2:定时器计数(用useRef保存定时器ID,避免重复创建)
  const startTimer = () => {
    if (timerRef.current) return; // 避免重复启动定时器
    timerRef.current = setInterval(() => {
      // 定时器中用函数式更新,确保获取最新的count
      setCount(prevCount => prevCount + 1);
    }, 1000);
  };

  const stopTimer = () => {
    // 清除定时器(用useRef保存的ID)
    clearInterval(timerRef.current);
    timerRef.current = null;
  };

  // 组件卸载时清除定时器,避免内存泄漏
  useEffect(() => {
    return () => {
      clearInterval(timerRef.current);
    };
  }, []);

  return (
    <div style="{{" padding: 24, width: 400 }}>
      <h3>useRef 双场景示例</h3>
      {/* 输入框:ref={inputRef} 绑定DOM引用 */}
      <input ref="{inputRef}" placeholder="我会自动聚焦" style="{{" marginBottom: 16 }}>
      <button onclick="{handleFocusInput}" style="{{" marginbottom: 16 }}>
        让输入框聚焦
      </button>

      <divider />

      <div style="{{" marginbottom: 16 }}>
        <span>定时器计数:{count} 秒</span>
      </div>
      <space size="middle">
        <button onclick="{startTimer}" type="primary">
          开始计数
        </button>
        <button onclick="{stopTimer}" danger>
          停止计数
        </button>
      </space>
    </div>
  );
};

export default UseRefDemo;

2. React useReducer Hook 详解:什么时候用它代替 useState?

核心作用

useReducer是“复杂状态管理”的 Hook,它接收一个“ reducer 函数”和“初始状态”,返回当前状态和“dispatch 函数”(用于触发状态更新)。

当状态满足以下条件时,用useReduceruseState更合适(国内项目高频场景):

  • 状态是“对象/数组”(如购物车商品列表、表单多字段);
  • 状态更新逻辑复杂(如购物车的“添加/删除/修改数量/清空”);
  • 多个子组件需要修改同一状态(通过 dispatch 统一触发)。

国内项目示例:电商购物车(useReducer 实战)

import React, { useReducer } from 'react';
import { Card, List, Button, InputNumber, Space, message } from 'antd';

// 1. 定义reducer函数(处理状态更新逻辑)
// state:当前状态;action:描述“做什么”(type+payload)
const cartReducer = (state, action) =&gt; {
  switch (action.type) {
    // 1. 添加商品到购物车
    case 'ADD_ITEM': {
      // 检查商品是否已在购物车中
      const existingItem = state.find(item =&gt; item.id === action.payload.id);
      if (existingItem) {
        // 已存在:更新数量
        return state.map(item =&gt; 
          item.id === action.payload.id 
            ? { ...item, quantity: item.quantity + action.payload.quantity }
            : item
        );
      } else {
        // 不存在:新增商品
        return [...state, action.payload];
      }
    }
    // 2. 修改商品数量
    case 'UPDATE_QUANTITY':
      return state.map(item =&gt; 
        item.id === action.payload.id 
          ? { ...item, quantity: action.payload.quantity }
          : item
      );
    // 3. 删除商品
    case 'REMOVE_ITEM':
      return state.filter(item =&gt; item.id !== action.payload.id);
    // 4. 清空购物车
    case 'CLEAR_CART':
      return [];
    // 默认:返回原状态
    default:
      return state;
  }
};

// 2. 购物车组件
const ShoppingCart = () =&gt; {
  // 初始化购物车状态(国内电商常见的商品结构)
  const initialState = [
    { id: 1, name: '华为Mate 60 Pro', price: 6999, quantity: 1, img: '/images/mate60.jpg' },
    { id: 2, name: '小米14', price: 4999, quantity: 1, img: '/images/mi14.jpg' },
  ];

  // 调用useReducer:获取state和dispatch
  const [cartItems, dispatch] = useReducer(cartReducer, initialState);

  // 计算总价(国内电商购物车必备)
  const totalPrice = cartItems.reduce(
    (total, item) =&gt; total + item.price * item.quantity,
    0
  );

  // 触发状态更新的方法(调用dispatch,传递action)
  const addItem = () =&gt; {
    // 模拟添加新商品
    const newItem = {
      id: 3,
      name: 'iPhone 15',
      price: 7999,
      quantity: 1,
      img: '/images/iphone15.jpg',
    };
    dispatch({ type: 'ADD_ITEM', payload: newItem });
    message.success('商品已添加到购物车');
  };

  const updateQuantity = (id, quantity) =&gt; {
    // 数量不能小于1
    if (quantity &lt; 1) return;
    dispatch({ type: 'UPDATE_QUANTITY', payload: { id, quantity } });
  };

  const removeItem = (id) =&gt; {
    dispatch({ type: 'REMOVE_ITEM', payload: { id } });
  };

  const clearCart = () =&gt; {
    dispatch({ type: 'CLEAR_CART' });
  };

  return (
    <card title="我的购物车" style="{{" width: 800, margin: '0 auto', padding: 24 }}>
      {cartItems.length === 0 ? (
        <div style="{{" textalign: 'center', padding: 40 }}>
          <p>购物车为空</p>
          <button onclick="{addItem}" type="primary">
            添加示例商品
          </button>
        </div>
      ) : (
        &lt;&gt;
          <list datasource="{cartItems}" renderitem="{(item)" => (
              <list.item key="{item.id}" actions="{[" <button danger onclick="{()" => removeItem(item.id)}&gt;
                    删除
                  
                ]}
              &gt;
                <list.item.meta avatar="{<img" src="{item.img}" alt="{item.name}" style="{{" width: 60, height: 60 }} />}
                  title={item.name}
                  description={`单价:¥${item.price}`}
                /&gt;
                <div>
                  {/* 数量调整:国内电商常见的InputNumber */}
                  <inputnumber min="{1}" value="{item.quantity}" onchange="{(quantity)" => updateQuantity(item.id, quantity)}
                    style={{ marginRight: 16 }}
                  /&gt;
                  <span style="{{" color: '#f40' }}>¥{item.price * item.quantity}</span>
                </inputnumber></div>
              </list.item>
            )}
          /&gt;
          <div style="{{" textalign: 'right', margintop: 16 }}>
            <space size="middle">
              <button onclick="{clearCart}">清空购物车</button>
              <button onclick="{addItem}" type="primary">
                添加商品
              </button>
              <div style="{{" fontsize: 18, color: '#f40' }}>
                总价:¥{totalPrice.toFixed(2)}
              </div>
            </space>
          </div>
        
      )}
    </list></card>
  );
};

export default ShoppingCart;

3. React 中的 useMemo:通过记忆化优化性能

核心作用

useMemo是“记忆化值”的 Hook,它接收一个“计算函数”和“依赖数组”,只有当依赖数组中的值变化时,才会重新执行计算函数并返回新值;否则直接返回“缓存的旧值”。

国内开发中,useMemo主要用于优化“昂贵的计算”(如大数据排序、复杂列表过滤),避免组件每次重渲染时都重复执行耗时计算,导致页面卡顿。

国内项目示例:大数据列表过滤(useMemo 优化)

import React, { useState, useMemo } from 'react';
import { Input, List, Card, Spin } from 'antd';

// 模拟大数据(国内后台常见的“用户列表”,1000条数据)
const generateBigData = () =&gt; {
  return Array.from({ length: 1000 }, (_, i) =&gt; ({
    id: i + 1,
    username: `user_${i + 1}`,
    role: i % 3 === 0 ? '管理员' : i % 3 === 1 ? '编辑' : '普通用户',
    department: `部门_${Math.floor(i / 100) + 1}`,
  }));
};

const BigDataFilter = () =&gt; {
  const [searchText, setSearchText] = useState('');
  const bigData = generateBigData(); // 模拟接口返回的大数据

  // 昂贵的计算:根据搜索框过滤数据(遍历1000条数据)
  // 用useMemo记忆化结果:只有searchText变化时才重新过滤
  const filteredData = useMemo(() =&gt; {
    console.log('执行过滤计算(仅searchText变化时触发)');
    // 模拟耗时计算(实际项目中可能更复杂)
    return bigData.filter(item =&gt; 
      item.username.includes(searchText) || 
      item.role.includes(searchText) || 
      item.department.includes(searchText)
    );
  }, [searchText, bigData]); // 依赖:searchText或bigData变化时重新计算

  // 普通计算(无useMemo):每次组件重渲染都会执行
  const unoptimizedData = bigData.filter(item =&gt; 
    item.username.includes(searchText)
  );
  console.log('未优化的过滤计算(每次重渲染都触发)');

  return (
    <card title="大数据列表过滤(useMemo优化)" style="{{" width: 800, margin: '0 auto', padding: 24 }}>
      {/* 搜索框:输入变化触发组件重渲染 */}
      <input placeholder="搜索用户名/角色/部门" value="{searchText}" onChange="{(e)" => setSearchText(e.target.value)}
        style={{ marginBottom: 16 }}
      /&gt;

      <h4>优化后的数据(useMemo):{filteredData.length} 条</h4>
      <list datasource="{filteredData}" renderitem="{(item)" => (
          <list.item key="{item.id}">
            <span>{item.username}</span> · 
            <span style="{{" margin: '0 8px' }}>{item.role}</span> · 
            <span>{item.department}</span>
          </list.item>
        )}
        pagination={{ pageSize: 10 }}
        style={{ marginBottom: 24 }}
      /&gt;

      <h4>未优化的数据(无useMemo):{unoptimizedData.length} 条</h4>
      <list datasource="{unoptimizedData}" renderitem="{(item)" => (
          <list.item key="{item.id}">{item.username}</list.item>
        )}
        pagination={{ pageSize: 10 }}
      /&gt;
    </list></list></card>
  );
};

export default BigDataFilter;

注意点(国内开发者常踩的坑)

  • useMemo不是“越多越好”:简单计算(如a + b)用useMemo反而会增加缓存开销,只优化“耗时计算”;
  • 依赖数组必须完整:如果计算函数中用到了组件内的状态/属性,必须加到依赖数组中,否则会获取到过时的值。

4. React 中的 useCallback:记忆化函数避免重复创建

核心作用

useCallback是“记忆化函数”的 Hook,它接收一个“函数”和“依赖数组”,只有当依赖数组中的值变化时,才会返回新的函数;否则直接返回“缓存的旧函数”。

国内开发中,useCallback主要用于解决“子组件不必要的重渲染”问题——当父组件传给子组件的函数“每次都重新创建”时,即使子组件用了React.memo(记忆化组件),也会触发重渲染。用useCallback缓存函数,能让子组件只在必要时重渲染。

国内项目示例:父子组件优化(useCallback+React.memo)

import React, { useState, useCallback } from 'react';
import { Button, Card, Space } from 'antd';

// 子组件:商品卡片(用React.memo记忆化,避免不必要重渲染)
const ProductItem = React.memo(({ product, onAddToCart }) =&gt; {
  console.log(`商品 ${product.name} 组件重渲染`); // 查看重渲染情况

  return (
    <card title="{product.name}" style="{{" width: 240, margin: '16px' }}>
      <p>价格:¥{product.price}</p>
      <button type="primary" danger onclick="{()" => onAddToCart(product.id)}
        style={{ width: '100%', marginTop: 12 }}
      &gt;
        加入购物车
      </button>
    </card>
  );
});

// 父组件:商品列表
const ProductList = () =&gt; {
  const [count, setCount] = useState(0); // 父组件状态(与子组件无关)
  const [products] = useState([
    { id: 1, name: '华为Mate 60 Pro', price: 6999 },
    { id: 2, name: '小米14', price: 4999 },
    { id: 3, name: 'iPhone 15', price: 7999 },
  ]);

  // 未优化的函数:每次父组件重渲染都会创建新函数
  const unoptimizedAddToCart = (productId) =&gt; {
    console.log(`添加商品 ${productId} 到购物车`);
  };

  // 优化的函数:用useCallback缓存,只有依赖变化时才创建新函数
  const optimizedAddToCart = useCallback((productId) =&gt; {
    console.log(`添加商品 ${productId} 到购物车`);
    // 如果函数中用到count,需要把count加到依赖数组中
    // console.log('当前购物车数量:', count);
  }, []); // 依赖数组:此处无依赖,函数永远是同一个引用

  return (
    <div style="{{" padding: 24 }}>
      <h2>商品列表(useCallback优化)</h2>
      {/* 点击按钮修改count,触发父组件重渲染 */}
      <space style="{{" marginbottom: 16 }}>
        <button onclick="{()" => setCount(count + 1)}&gt;
          点击触发父组件重渲染(count:{count})
        </button>
        <p>观察控制台:子组件是否重渲染</p>
      </space>

      <h4>未优化的子组件(传普通函数)</h4>
      <div style="{{" display: 'flex', flexwrap: 'wrap' }}>
        {products.map(product =&gt; (
          <productitem key="{product.id}" product="{product}" onAddToCart="{unoptimizedAddToCart}" 每次都传新函数 />
        ))}
      </div>

      <h4 style="{{" margintop: 24 }}>优化的子组件(传useCallback缓存的函数)</h4>
      <div style="{{" display: 'flex', flexwrap: 'wrap' }}>
        {products.map(product =&gt; (
          <productitem key="{product.id}" product="{product}" onAddToCart="{optimizedAddToCart}" 传缓存的函数 />
        ))}
      </div>
    </div>
  );
};

export default ProductList;

关键搭配

useCallback通常和React.memo一起使用:

  • React.memo:让子组件只在 props 变化时重渲染;
  • useCallback:确保父组件传给子组件的函数“不轻易变化”,避免React.memo失效。

5. 创建 React 自定义 Hook:复用组件逻辑

核心作用

自定义 Hook 是“抽取和复用组件逻辑”的方式,它本质是“命名以 use 开头的函数”,可以调用其他 Hook(如useStateuseEffect)。

国内开发中,自定义 Hook 能解决“逻辑重复”问题——比如多个组件都需要“获取用户位置”“处理表单验证”“监听滚动事件”,把这些逻辑抽成自定义 Hook,能让代码更简洁、易维护。

国内项目示例:3 个高频自定义 Hook(表单验证+接口请求+滚动监听)

import React, { useState, useEffect, useCallback } from 'react';
import { Input, Button, message, Form } from 'antd';

// 自定义Hook 1:表单验证(国内表单高频需求)
const useFormValidation = (initialValues, validateRules) =&gt; {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  const [isValid, setIsValid] = useState(false);

  // 验证逻辑
  const validate = useCallback(() =&gt; {
    const newErrors = {};
    // 遍历验证规则(如必填、手机号格式)
    Object.entries(validateRules).forEach(([key, rule]) =&gt; {
      const value = values[key];
      if (rule.required &amp;&amp; !value) {
        newErrors[key] = rule.message || `${key}不能为空`;
      } else if (rule.pattern &amp;&amp; value &amp;&amp; !rule.pattern.test(value)) {
        newErrors[key] = rule.message || `${key}格式错误`;
      }
    });
    setErrors(newErrors);
    setIsValid(Object.keys(newErrors).length === 0);
    return newErrors;
  }, [values, validateRules]);

  // 输入变化时更新值
  const handleChange = (e) =&gt; {
    const { name, value } = e.target;
    setValues(prev =&gt; ({ ...prev, [name]: value }));
  };

  // 提交前验证
  const handleSubmit = (onSubmit) =&gt; () =&gt; {
    const newErrors = validate();
    if (Object.keys(newErrors).length === 0) {
      onSubmit(values);
    }
  };

  return { values, errors, isValid, handleChange, handleSubmit, validate };
};

// 自定义Hook 2:接口请求(国内项目通用请求逻辑)
const useFetch = (url, options = {}) =&gt; {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchData = useCallback(async () =&gt; {
    setLoading(true);
    try {
      const res = await fetch(url, {
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });
      if (!res.ok) throw new Error(`请求失败:${res.status}`);
      const result = await res.json();
      setData(result);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData(null);
      message.error(err.message);
    } finally {
      setLoading(false);
    }
  }, [url, options]);

  // 初始请求(如果需要)
  useEffect(() =&gt; {
    if (options.autoFetch !== false) {
      fetchData();
    }
  }, [fetchData, options.autoFetch]);

  return { data, loading, error, refetch: fetchData };
};

// 自定义Hook 3:滚动监听(国内H5高频需求)
const useScroll监听 = (targetId) =&gt; {
  const [isScrolledToTarget, setIsScrolledToTarget] = useState(false);

  useEffect(() =&gt; {
    const handleScroll = () =&gt; {
      const targetElement = document.getElementById(targetId);
      if (!targetElement) return;

      // 计算目标元素是否进入视口
      const rect = targetElement.getBoundingClientRect();
      const isInView = rect.top &lt;= window.innerHeight / 2 &amp;&amp; rect.bottom &gt;= 0;
      setIsScrolledToTarget(isInView);
    };

    window.addEventListener('scroll', handleScroll);
    handleScroll(); // 初始检查

    return () =&gt; {
      window.removeEventListener('scroll', handleScroll);
    };
  }, [targetId]);

  return isScrolledToTarget;
};

// 使用自定义Hook:表单组件
const LoginForm = () =&gt; {
  // 使用useFormValidation
  const { values, errors, handleChange, handleSubmit } = useFormValidation(
    { username: '', phone: '' }, // 初始值
    { // 验证规则
      username: { required: true, message: '请输入用户名' },
      phone: { 
        required: true, 
        message: '请输入手机号', 
        pattern: /^1[3-9]\d{9}$/ // 国内手机号正则
      },
    }
  );

  // 表单提交
  const onLogin = (values) =&gt; {
    console.log('登录提交:', values);
    message.success('登录验证通过');
  };

  return (
    <form style="{{" width: 350, margin: '0 auto' }}>
      <form.item label="用户名" validatestatus="{errors.username" ? 'error' : ''} help="{errors.username}">
        <input name="username" value="{values.username}" onChange="{handleChange}" placeholder="请输入用户名">
      </form.item>
      <form.item label="手机号" validatestatus="{errors.phone" ? 'error' : ''} help="{errors.phone}">
        <input name="phone" value="{values.phone}" onChange="{handleChange}" placeholder="请输入手机号">
      </form.item>
      <form.item>
        <button type="primary" onclick="{handleSubmit(onLogin)}" style="{{" width: '100%' }}>
          登录
        </button>
      </form.item>
    </form>
  );
};

// 使用自定义Hook:接口请求组件
const UserData = () =&gt; {
  // 使用useFetch请求用户信息(autoFetch: true 初始自动请求)
  const { data, loading } = useFetch('/api/user', { autoFetch: true });

  if (loading) return <spin style="{{" display: 'block', margin: '40px auto' }} />;

  return (
    <div style="{{" padding: 24 }}>
      <h3>用户信息</h3>
      {data &amp;&amp; (
        <div>
          <p>用户名:{data.username}</p>
          <p>手机号:{data.phone}</p>
          <p>角色:{data.role}</p>
        </div>
      )}
    </div>
  );
};

// 组合使用
const CustomHooksDemo = () =&gt; {
  // 使用useScroll监听:监听id为"target"的元素
  const isTargetInView = useScroll监听('target');

  return (
    <div style="{{" padding: 24 }}>
      <h2>自定义Hook示例</h2>
      <loginform />
      <userdata />
      <div style="{{" height: 1000 }}> {/* 占位,让页面可滚动 */}
        <p>滚动到下方目标区域...</p>
      </div>
      <div id="target" style="{{" padding: 24, background: istargetinview ? '#f0f7ff' : '#fff', border: '1px solid #1890ff' #eee' }}>
        <h3>目标区域</h3>
        <p>{isTargetInView ? '已进入视口' : '未进入视口'}</p>
      </div>
    </div>
  );
};

export default CustomHooksDemo;

6. 最常用 React Hooks 对比:什么时候用哪个?

核心问题

国内开发者在实际开发中,常困惑“该用 useState 还是 useReducer?”“useMemo 和 useCallback 有啥区别?”——这部分通过对比表格和场景总结,帮你快速判断“什么场景用什么 Hook”。

1. 状态管理类 Hook 对比(useState vs useReducer)

对比维度 useState useReducer
适用场景 简单状态(数字、字符串、简单对象) 复杂状态(多字段对象、数组,复杂更新逻辑)
状态更新逻辑 直接在 setter 中写(如setCount(c+1) 集中在 reducer 函数中(统一管理)
组件通信 需手动传 setter 给子组件 传 dispatch 给子组件(更简洁)
调试体验 难追踪状态变化原因 可通过 action type 追踪状态变化
国内项目示例 计数器、输入框内容、弹窗显示/隐藏 购物车、表单多字段、复杂列表状态

2. 性能优化类 Hook 对比(useMemo vs useCallback)

对比维度 useMemo useCallback
作用对象 记忆化“值”(如计算结果、数组) 记忆化“函数”(如事件处理函数、回调函数)
返回值 记忆化后的值 记忆化后的函数引用
适用场景 优化昂贵的计算(如大数据过滤、排序) 避免子组件不必要的重渲染(配合 React.memo)
国内项目示例 大数据列表过滤结果、图表计算数据 父组件传给子组件的事件处理函数、列表项点击函数

3. 其他常用 Hook 适用场景

Hook 核心作用 国内项目高频场景
useContext 跨层级传递数据,避免属性透传 全局主题、用户信息、语言设置
useRef 操作 DOM、保存持久化数据(不触发重渲染) 输入框聚焦、保存定时器 ID、获取最新状态
useEffect 管理副作用(请求、DOM 操作、定时器) 接口请求、监听事件、清理定时器

4. 国内项目 Hook 选择流程图(简化版)

  1. **需要管理状态?**→ 简单状态(1-2 个字段)→ useState→ 复杂状态(多字段/复杂更新)→ useReducer
  2. **需要处理副作用?**→ 请求数据、监听事件、清理资源 → useEffect
  3. **需要跨层级传数据?**→ 创建 Context + useContext
  4. **需要优化性能?**→ 优化计算结果 → useMemo→ 优化函数传递 → useCallback(配合 React.memo)
  5. **需要操作 DOM 或保存持久化数据?**→ useRef

下篇小结

这 6 个进阶概念,是 React 项目“从能用 to 好用”的关键:

  • useRef帮你解决“DOM 操作”和“持久化数据”的问题;
  • useReducer让复杂状态管理更清晰;
  • useMemo/useCallback帮你优化性能,避免页面卡顿;
  • 自定义 Hook 让逻辑复用更简单;
  • Hooks 对比表则帮你快速选择合适的工具。

掌握这些概念后,你不仅能应对国内大部分 React 业务场景(如电商、后台、H5),还能写出更易维护、性能更好的代码——这也是从“初级 React 开发者”到“中级开发者”的核心跨越。

原文链接:https://my.oschina.net/powertoolsteam/blog/18693307
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章