React 16 到 React 19 基础语法、API 对比与最佳实践

大家好,我是鱼樱!!!

关注公众号【鱼樱AI实验室】持续每天分享更多前端和AI辅助前端编码新知识~~喜欢的就一起学反正开源至上,无所谓被诋毁被喷被质疑文章没有价值~

一个城市淘汰的自由职业-农村前端程序员(虽然不靠代码挣钱,写文章就是为爱发电),兼职远程上班目前!!!热心坚持分享~~

1. 组件定义方式演变

1.1 类组件与函数组件

React 16:

jsx 复制代码
// 类组件
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

// 函数组件(无状态)
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

React 16.8+:

jsx 复制代码
// 函数组件(有状态)
function Welcome(props) {
  const [count, setCount] = useState(0);
  return <h1>Hello, {props.name}, Count: {count}</h1>;
}

最佳实践:

  • React 16-19: 优先使用函数组件和 Hooks,类组件仅用于维护旧代码
  • React 18+: 利用并发特性时,建议使用函数组件,类组件不支持某些新功能

2. 生命周期详细对比

2.1 类组件生命周期变化

React 16.0-16.2:

jsx 复制代码
class Component extends React.Component {
  constructor(props) {
    super(props);
    // 初始化状态
  }
  
  componentWillMount() {
    // 组件挂载前 (已弃用)
  }
  
  componentDidMount() {
    // 组件挂载后
  }
  
  componentWillReceiveProps(nextProps) {
    // 组件接收新props前 (已弃用)
  }
  
  shouldComponentUpdate(nextProps, nextState) {
    // 控制是否重新渲染
    return true;
  }
  
  componentWillUpdate(nextProps, nextState) {
    // 组件更新前 (已弃用)
  }
  
  componentDidUpdate(prevProps, prevState) {
    // 组件更新后
  }
  
  componentWillUnmount() {
    // 组件卸载前
  }
}

React 16.3:

jsx 复制代码
class Component extends React.Component {
  // 新增
  static getDerivedStateFromProps(props, state) {
    // 在render前调用,用于根据props更新state
    // 替代componentWillReceiveProps
    return null; // 返回null表示不更新状态
  }
  
  // 新增
  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 在DOM更新前调用,返回值会传递给componentDidUpdate
    // 替代componentWillUpdate
    return null;
  }
  
  componentDidUpdate(prevProps, prevState, snapshot) {
    // snapshot是getSnapshotBeforeUpdate的返回值
  }
}

React 16.3-16.8 弃用的生命周期:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

这些方法被标记为 UNSAFE_ 前缀版本:

  • UNSAFE_componentWillMount
  • UNSAFE_componentWillReceiveProps
  • UNSAFE_componentWillUpdate

React 17+ 完整生命周期:

jsx 复制代码
class Component extends React.Component {
  constructor(props)
  
  static getDerivedStateFromProps(props, state)
  
  shouldComponentUpdate(nextProps, nextState)
  
  render()
  
  getSnapshotBeforeUpdate(prevProps, prevState)
  
  componentDidMount()
  
  componentDidUpdate(prevProps, prevState, snapshot)
  
  componentWillUnmount()
  
  // 错误处理
  static getDerivedStateFromError(error)
  
  componentDidCatch(error, info)
}

2.2 函数组件生命周期(Hooks)

React 16.8+ Hooks:

jsx 复制代码
function Component(props) {
  // 相当于constructor和componentDidMount, componentDidUpdate, componentWillUnmount的组合
  useEffect(() => {
    // 相当于componentDidMount和componentDidUpdate
    console.log('组件挂载或更新后');
    
    return () => {
      // 相当于componentWillUnmount
      console.log('组件卸载前');
    };
  }, [/* 依赖数组 */]);
  
  // 仅在挂载时执行一次
  useEffect(() => {
    console.log('仅在组件挂载后');
    return () => {
      console.log('组件卸载前清理');
    };
  }, []);
  
  // 每次渲染后都执行
  useEffect(() => {
    console.log('每次渲染后执行');
  });
  
  // 根据特定依赖更新
  useEffect(() => {
    console.log('props.id变化时执行');
  }, [props.id]);
  
  // 相当于componentDidMount, componentDidUpdate和getSnapshotBeforeUpdate
  useLayoutEffect(() => {
    // DOM更新后、浏览器绘制前同步执行
  }, []);
}

React 18+ 新添加的 Hook:

jsx 复制代码
function Component() {
  // 仅服务端渲染期间执行一次
  useInsertionEffect(() => {
    // 用于CSS-in-JS库注入样式
    // 在DOM创建后,useLayoutEffect前执行
  }, []);
  
  // 延迟执行,不阻塞渲染
  const deferredValue = useDeferredValue(value);
  
  // 过渡更新,标记非紧急更新
  const [isPending, startTransition] = useTransition();
  
  // React 18.2+,组件ID
  const id = useId();
  
  // React 18+,Suspense缓存
  useCacheRefresh();
}

React 19+ Hooks:

jsx 复制代码
function Component() {
  // React 19 新增action hook管理表单状态
  const formAction = useFormAction({
    // 表单状态管理
  });
  
  // 新的effect优化API,减少重渲染
  useEffectEvent(() => {
    // 执行不需要重新渲染的逻辑
  });
}

2.3 类组件与函数组件生命周期对比表

类组件 函数组件(Hooks) 执行时机
constructor useState, useRef初始化 组件创建时
getDerivedStateFromProps 在渲染过程中通过计算获取 render前
shouldComponentUpdate React.memo, useMemo 决定是否重新渲染
render 函数本体 渲染组件
getSnapshotBeforeUpdate useLayoutEffect(有限接近) DOM更新前
componentDidMount useEffect([], ...) 组件挂载后
componentDidUpdate useEffect([deps], ...) 组件更新后
componentWillUnmount useEffect返回的函数 组件卸载前
getDerivedStateFromError 无直接对应,需使用错误边界 子组件出错时
componentDidCatch 无直接对应,需使用错误边界 捕获子组件错误后

3. 状态管理演变

3.1 类组件状态管理

React 16:

jsx 复制代码
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  
  increment = () => {
    this.setState({ count: this.state.count + 1 });
    // 或使用函数式更新
    this.setState(state => ({ count: state.count + 1 }));
  }
  
  render() {
    return (
      <button onClick={this.increment}>
        Count: {this.state.count}
      </button>
    );
  }
}

3.2 函数组件状态管理

React 16.8+:

jsx 复制代码
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

React 18: 自动批处理更新 - 多个状态更新合并为一次渲染

jsx 复制代码
function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);
  
  function handleClick() {
    // React 18中这些会被自动批处理为一次更新
    setCount(c => c + 1); // 不会触发重新渲染
    setFlag(f => !f);     // 只有这后会触发一次重新渲染
  }
  
  // ...
}

React 19: 引入更细粒度的状态管理,useActionState帮助管理表单状态

jsx 复制代码
function Form() {
  const [state, action] = useActionState({
    initialState: { name: "" },
    action: (state, newValue) => {
      return { ...state, ...newValue }
    }
  });
  
  return <form action={action}>
    <input name="name" defaultValue={state.name} />
  </form>;
}

3.3 状态管理最佳实践

  • React 16-19:
    • 使用函数式更新处理依赖前一状态的更新
    • 对象状态更新时保持不可变性
  • React 18+:
    • 利用自动批处理优化性能
    • 使用 useDeferredValue 和 useTransition 处理大型状态更新
  • React 19+:
    • 使用新的表单状态管理API简化表单处理

4. Props 处理与组件通信

4.1 Props 默认值

类组件:

jsx 复制代码
class Button extends React.Component {
  static defaultProps = {
    color: 'blue'
  };
  
  render() {
    return <button className={this.props.color}>{this.props.children}</button>;
  }
}

函数组件:

jsx 复制代码
function Button({ color = 'blue', children }) {
  return <button className={color}>{children}</button>;
}

// 或者
Button.defaultProps = {
  color: 'blue'
};

4.2 Props 类型检查

React 16-19:

jsx 复制代码
import PropTypes from 'prop-types';

function Button({ color, children }) {
  return <button className={color}>{children}</button>;
}

Button.propTypes = {
  color: PropTypes.string,
  children: PropTypes.node.isRequired
};

TypeScript (推荐):

tsx 复制代码
interface ButtonProps {
  color?: string;
  children: React.ReactNode;
}

function Button({ color = 'blue', children }: ButtonProps) {
  return <button className={color}>{children}</button>;
}

4.3 Context API 演变

React 16.0:

jsx 复制代码
// 创建Context
const ThemeContext = React.createContext('light');

// 提供Context
class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <ThemedButton />
      </ThemeContext.Provider>
    );
  }
}

// 消费Context
class ThemedButton extends React.Component {
  static contextType = ThemeContext;
  
  render() {
    return <button theme={this.context}>Themed Button</button>;
  }
}

// 函数组件使用Consumer
function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {value => <button theme={value}>Themed Button</button>}
    </ThemeContext.Consumer>
  );
}

React 16.8+ (Hooks):

jsx 复制代码
const ThemeContext = React.createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button theme={theme}>Themed Button</button>;
}

5. 渲染优化各版本对比

5.1 类组件优化

React 16:

jsx 复制代码
class ExpensiveComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    // 手动控制重新渲染
    return this.props.value !== nextProps.value;
  }
  
  render() {
    return <div>{this.props.value}</div>;
  }
}

// 或使用PureComponent
class OptimizedComponent extends React.PureComponent {
  // 自动浅比较props和state
  render() {
    return <div>{this.props.value}</div>;
  }
}

5.2 函数组件优化

React 16.8+:

jsx 复制代码
// React.memo - 类似PureComponent的函数组件版本
const MemoizedComponent = React.memo(function MyComponent(props) {
  return <div>{props.value}</div>;
});

// 自定义比较函数
const MemoizedCustomComponent = React.memo(
  function MyComponent(props) {
    return <div>{props.value}</div>;
  },
  (prevProps, nextProps) => {
    // 返回true表示不重新渲染
    return prevProps.value === nextProps.value;
  }
);

function App() {
  // useMemo - 缓存计算结果
  const expensiveValue = useMemo(() => {
    return computeExpensiveValue(a, b);
  }, [a, b]);
  
  // useCallback - 缓存函数引用
  const memoizedCallback = useCallback(() => {
    doSomething(a, b);
  }, [a, b]);
}

React 18+:

jsx 复制代码
function SearchResults() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  
  // 输入时立即更新query,但延迟更新结果,提升用户体验
  const deferredQuery = useDeferredValue(query);
  
  useEffect(() => {
    fetchResults(deferredQuery).then(setResults);
  }, [deferredQuery]);
  
  return (
    <>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      {/* 可能很慢的渲染 */}
      <ResultsList query={deferredQuery} results={results} />
    </>
  );
}

React 19+:

jsx 复制代码
// React 19中的自动记忆
function ResultItem({item}) {
  return <div className="item">{item.title}</div>;
}

// React会自动优化类似上述纯渲染组件
function ResultsList({items}) {
  return (
    <div>
      {items.map(item => <ResultItem key={item.id} item={item} />)}
    </div>
  );
}

6. 副作用处理

6.1 类组件

React 16:

jsx 复制代码
class DataFetcher extends React.Component {
  state = { data: null, loading: true };
  
  componentDidMount() {
    this.fetchData();
  }
  
  componentDidUpdate(prevProps) {
    if (prevProps.id !== this.props.id) {
      this.fetchData();
    }
  }
  
  componentWillUnmount() {
    // 清理工作
    this.isUnmounted = true;
  }
  
  fetchData = async () => {
    this.setState({ loading: true });
    const data = await fetchAPI(this.props.id);
    
    // 防止组件卸载后设置状态
    if (!this.isUnmounted) {
      this.setState({ data, loading: false });
    }
  }
  
  render() {
    // ...
  }
}

6.2 函数组件

React 16.8+:

jsx 复制代码
function DataFetcher({ id }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    let isMounted = true;
    setLoading(true);
    
    fetchAPI(id).then(data => {
      if (isMounted) {
        setData(data);
        setLoading(false);
      }
    });
    
    return () => {
      isMounted = false; // 清理函数
    };
  }, [id]); // 依赖数组,id变化时重新执行
  
  // ...
}

React 18+: 使用useTransition处理副作用

jsx 复制代码
function SearchResults() {
  const [isPending, startTransition] = useTransition();
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  
  function handleChange(e) {
    // 立即更新输入值
    setQuery(e.target.value);
    
    // 标记结果更新为非紧急
    startTransition(async () => {
      const results = await fetchResults(e.target.value);
      setResults(results);
    });
  }
  
  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending ? (
        <div>Loading...</div>
      ) : (
        <ResultsList results={results} />
      )}
    </>
  );
}

7. 错误处理

7.1 错误边界

React 16+:

jsx 复制代码
class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };
  
  static getDerivedStateFromError(error) {
    // 更新状态,下次渲染显示备用UI
    return { hasError: true, error };
  }
  
  componentDidCatch(error, info) {
    // 记录错误信息
    logErrorToService(error, info);
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    
    return this.props.children;
  }
}

// 使用
<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

注意: 截至React 19,仍然没有函数组件版本的错误边界,必须使用类组件。

7.2 React 18+ 新错误处理能力

jsx 复制代码
// React 18新增全局API
function App() {
  return (
    <React.StrictMode>
      <ErrorBoundary
        fallback={<p>Application Error</p>}
        onError={(error, errorInfo) => {
          // 记录到服务
          logError(error, errorInfo);
        }}
      >
        <AppContent />
      </ErrorBoundary>
    </React.StrictMode>
  );
}

8. React 16 到 19 的重要 API 变更

8.1 新增API

API 版本 描述
React.lazy 16.6 组件代码分割
React.Suspense 16.6 等待加载组件
React.memo 16.6 函数组件性能优化
Hooks系列API 16.8 函数组件状态和生命周期
React.createRoot 18.0 新并发渲染器入口
useTransition 18.0 标记非紧急更新
useDeferredValue 18.0 延迟低优先级更新
useId 18.0 生成唯一ID
useInsertionEffect 18.0 CSS-in-JS库专用Hook
useFormState 19.0 表单状态管理
useFormStatus 19.0 表单提交状态
useEffectEvent 19.0 分离事件逻辑和渲染依赖
useOptimistic 19.0 乐观UI更新

8.2 弃用API

API 弃用版本 替代方案
componentWillMount 16.3 componentDidMount
componentWillReceiveProps 16.3 getDerivedStateFromProps
componentWillUpdate 16.3 getSnapshotBeforeUpdate
ReactDOM.render 18.0 ReactDOM.createRoot().render()
ReactDOM.hydrate 18.0 ReactDOM.hydrateRoot()
findDOMNode 17.0 Refs

8.3 重大变更

React 17:

  • 事件委托变更 - 从document改为挂载React树的根DOM
  • 移除事件池
  • useEffect清理函数变为异步
  • 一致的错误边界行为

React 18:

  • 自动批处理state更新
  • 并发渲染
  • 服务器组件
  • Suspense支持服务端渲染
  • transitions用于区分紧急和非紧急更新

React 19:

  • 更好的表单API
  • 自动化记忆优化
  • 服务器Actions
  • 资产加载优化
  • 错误边界改进

9. 代码组织最佳实践

9.1 组件设计原则

单一职责:

jsx 复制代码
// 不推荐
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetchUser(userId).then(setUser);
    fetchPosts(userId).then(setPosts);
  }, [userId]);
  
  // 渲染用户信息和帖子列表...
}

// 推荐 - 分离关注点
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]);
  // 渲染用户信息...
}

function UserPosts({ userId }) {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    fetchPosts(userId).then(setPosts);
  }, [userId]);
  // 渲染帖子列表...
}

9.2 自定义Hook封装

jsx 复制代码
// 封装数据获取逻辑
function useFetch(url, options) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    let isMounted = true;
    setLoading(true);
    
    fetch(url, options)
      .then(res => res.json())
      .then(data => {
        if (isMounted) {
          setData(data);
          setError(null);
          setLoading(false);
        }
      })
      .catch(err => {
        if (isMounted) {
          setError(err);
          setData(null);
          setLoading(false);
        }
      });
      
    return () => {
      isMounted = false;
    };
  }, [url, JSON.stringify(options)]);
  
  return { data, loading, error };
}

// 使用
function UserProfile({ userId }) {
  const { data: user, loading, error } = useFetch(`/api/users/${userId}`);
  
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error loading user</p>;
  
  return <div>{user.name}</div>;
}

9.3 React 18+ 并发特性最佳实践

jsx 复制代码
function SearchPage() {
  const [searchTerm, setSearchTerm] = useState('');
  const [isPending, startTransition] = useTransition();
  
  function handleSearch(e) {
    // 立即更新输入值
    setSearchTerm(e.target.value);
    
    // 非紧急更新 - 搜索结果计算
    startTransition(() => {
      // 重量级操作...
    });
  }
  
  return (
    <>
      <input value={searchTerm} onChange={handleSearch} />
      {isPending ? <Spinner /> : <SearchResults term={searchTerm} />}
    </>
  );
}

9.4 React 19 表单处理最佳实践

jsx 复制代码
'use client';

import { useFormState, useFormStatus } from 'react';

// 服务端Action
async function signup(prevState, formData) {
  try {
    const user = await createUser(formData);
    return { success: true, user };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

function SubmitButton() {
  const { pending } = useFormStatus();
  
  return (
    <button disabled={pending}>
      {pending ? 'Signing up...' : 'Sign up'}
    </button>
  );
}

function SignupForm() {
  const [state, formAction] = useFormState(signup, {
    success: false,
    error: null
  });
  
  return (
    <form action={formAction}>
      {state.error && <p className="error">{state.error}</p>}
      {state.success && <p className="success">Account created!</p>}
      
      <input name="username" required />
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      
      <SubmitButton />
    </form>
  );
}

10. 性能优化策略

10.1 React 16-17 优化

  1. 虚拟列表渲染
jsx 复制代码
import { FixedSizeList } from 'react-window';

function List({ items }) {
  const renderRow = ({ index, style }) => (
    <div style={style}>
      {items[index].text}
    </div>
  );
  
  return (
    <FixedSizeList
      height={500}
      width={300}
      itemCount={items.length}
      itemSize={35}
    >
      {renderRow}
    </FixedSizeList>
  );
}
  1. 使用React.memo避免不必要渲染
jsx 复制代码
const ExpensiveComponent = React.memo(function ExpensiveComponent({ value }) {
  // 昂贵的渲染操作
  return <div>{value}</div>;
});
  1. 使用useMemo缓存计算值
jsx 复制代码
function FilteredList({ items, filterTerm }) {
  const filteredItems = useMemo(() => {
    return items.filter(item => 
      item.name.toLowerCase().includes(filterTerm.toLowerCase())
    );
  }, [items, filterTerm]);
  
  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

10.2 React 18 优化

  1. 使用useDeferredValue
jsx 复制代码
function SearchResults({ query }) {
  // 延迟处理搜索结果更新
  const deferredQuery = useDeferredValue(query);
  
  // 昂贵的过滤操作使用deferredQuery
  const results = useMemo(() => {
    return computeFilteredResults(deferredQuery);
  }, [deferredQuery]);
  
  return (
    <div>
      <p>Searching for: {query}</p>
      <ul>
        {results.map(result => (
          <li key={result.id}>{result.title}</li>
        ))}
      </ul>
    </div>
  );
}
  1. useTransition分离紧急和非紧急更新
jsx 复制代码
function TabContainer() {
  const [selectedTab, setSelectedTab] = useState('home');
  const [isPending, startTransition] = useTransition();
  
  function selectTab(tab) {
    // 标记为非紧急更新
    startTransition(() => {
      setSelectedTab(tab);
    });
  }
  
  return (
    <div>
      <TabButton 
        isSelected={selectedTab === 'home'}
        onClick={() => selectTab('home')}
      >
        Home
      </TabButton>
      <TabButton 
        isSelected={selectedTab === 'about'}
        onClick={() => selectTab('about')}
      >
        About
      </TabButton>
      
      {isPending ? <Spinner /> : <TabContent tab={selectedTab} />}
    </div>
  );
}

10.3 React 19 优化

  1. 使用自动记忆机制
jsx 复制代码
// React 19能自动优化这样的纯渲染组件
function Item({ text }) {
  return <div>{text}</div>;
}

// 在父组件中不需要额外缓存处理
function ItemsList({ items }) {
  return (
    <div>
      {items.map(item => <Item key={item.id} text={item.text} />)}
    </div>
  );
}
  1. 使用useOptimistic实现乐观UI更新
jsx 复制代码
function TodoList() {
  const [todos, setTodos] = useState([]);
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, { ...newTodo, pending: true }]
  );
  
  async function addTodo(text) {
    const newTodo = { id: Date.now(), text };
    
    // 立即显示乐观结果
    addOptimisticTodo(newTodo);
    
    try {
      // 执行实际API调用
      const savedTodo = await saveTodoToServer(newTodo);
      // 成功后更新实际状态
      setTodos([...todos, savedTodo]);
    } catch (error) {
      // 处理错误...
    }
  }
  
  return (
    <div>
      <AddTodoForm onAdd={addTodo} />
      <ul>
        {optimisticTodos.map(todo => (
          <TodoItem 
            key={todo.id}
            todo={todo}
            isPending={todo.pending}
          />
        ))}
      </ul>
    </div>
  );
}

11. 路由与代码分割

11.1 React Router 演变

React Router 5 (React 16-17):

jsx 复制代码
import { BrowserRouter, Route, Switch } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/users/:id" component={UserProfile} />
        <Route component={NotFound} />
      </Switch>
    </BrowserRouter>
  );
}

React Router 6 (React 18+):

jsx 复制代码
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users/:id" element={<UserProfile />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

11.2 代码分割

React 16.6+:

jsx 复制代码
import React, { Suspense } from 'react';

// 懒加载组件
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

React Router 6 与代码分割:

jsx 复制代码
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import React, { Suspense } from 'react';

const Home = React.lazy(() => import('./routes/Home'));
const About = React.lazy(() => import('./routes/About'));
const UserProfile = React.lazy(() => import('./routes/UserProfile'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/users/:id" element={<UserProfile />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

11.3 React 18+ 服务端组件

jsx 复制代码
// app/page.js - 服务器组件
export default async function Page() {
  // 直接在服务器上获取数据,不需要useEffect
  const data = await fetchData();
  
  return (
    <div>
      <h1>Server Component</h1>
      <ServerRenderedContent data={data} />
      <ClientInteractiveComponent />
    </div>
  );
}

// ClientInteractiveComponent.js
'use client'; // 标记为客户端组件

import { useState } from 'react';

export default function ClientInteractiveComponent() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

12. 测试策略

12.1 组件测试

使用Jest和React Testing Library:

jsx 复制代码
// Button.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';

test('renders button with correct text', () => {
  render(<Button>Click me</Button>);
  const buttonElement = screen.getByText(/click me/i);
  expect(buttonElement).toBeInTheDocument();
});

test('calls onClick when clicked', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Click me</Button>);
  fireEvent.click(screen.getByText(/click me/i));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

12.2 Hook测试

jsx 复制代码
// useCounter.test.js
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from './useCounter';

test('should increment counter', () => {
  const { result } = renderHook(() => useCounter());
  
  act(() => {
    result.current.increment();
  });
  
  expect(result.current.count).toBe(1);
});

12.3 React 18+ 并发模式测试

jsx 复制代码
// 测试useTransition
import { render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TransitionComponent from './TransitionComponent';

test('shows loading state during transition', async () => {
  render(<TransitionComponent />);
  
  // 点击触发transition
  await userEvent.click(screen.getByText('Load Data'));
  
  // 检查是否显示加载状态
  expect(screen.getByText('Loading...')).toBeInTheDocument();
  
  // 等待transition完成
  await screen.findByText('Data loaded');
  
  // 检查加载状态是否消失
  expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});

13. 版本迁移指南

13.1 从React 16到React 17

  1. 移除不安全生命周期方法

    • 重构 componentWillMountcomponentWillReceivePropscomponentWillUpdate
  2. 修复事件系统变化

    • 检查事件处理依赖于冒泡到document的代码
    • 事件池被移除,不再需要e.persist()
  3. JSX转换

    • 不再需要import React from 'react'(如果使用新JSX转换)

13.2 从React 17到React 18

  1. 更新渲染API

    jsx 复制代码
    // 旧版
    import ReactDOM from 'react-dom';
    ReactDOM.render(<App />, rootNode);
    
    // 新版
    import ReactDOM from 'react-dom/client';
    const root = ReactDOM.createRoot(rootNode);
    root.render(<App />);
  2. 处理自动批处理变化

    • 检查依赖于单独状态更新的代码
  3. 利用并发特性

    • 利用useTransition和useDeferredValue优化用户体验

13.3 从React 18到React 19

  1. 更新表单处理

    • 迁移到新表单APIs (useFormState, useFormStatus)
  2. 优化事件处理

    • 使用useEffectEvent分离事件逻辑
  3. 重构服务端组件

    • 更好地区分服务端和客户端组件

14. 综合最佳实践

14.1 组件设计

  • 使用函数组件和Hooks
  • 将复杂逻辑和状态抽离为自定义Hooks
  • 通过Props向下传递,通过Context共享全局状态
  • 避免过深的组件层级,考虑组合代替继承

14.2 状态管理

  • 局部状态使用useState和useReducer
  • 全局状态考虑使用Context或Redux
  • 使用不可变数据更新模式
  • React 18+中使用useDeferredValue和useTransition优化更新

14.3 副作用处理

  • 使用useEffect分类管理副作用
  • 正确设置依赖数组,避免遗漏
  • 使用清理函数防止内存泄漏
  • 使用fetch包装器如SWR或React Query优化数据获取

14.4 渲染优化

  • 使用React.memo包装纯组件
  • 使用useMemo缓存计算值
  • 使用useCallback稳定回调函数引用
  • 代码分割减少初始包大小
  • React 18+中使用startTransition标记非紧急更新

14.5 错误处理

  • 使用错误边界捕获组件树错误
  • 为Promise错误添加try/catch
  • 降级渲染处理错误状态

15. 总结

React 从16到19版本的演进展现了框架的不断成熟与优化。主要变化集中在:

  1. 编程模式变革: 从类组件到函数组件+Hooks的范式转变

  2. 响应式更新: 引入并发模式,更精细的更新优先级控制

  3. 服务器集成: 服务器组件的引入与完善

  4. 开发体验: 自动批处理、更好的工具和API设计

  5. 性能优化: 从手动优化到框架层自动优化

每个React版本都为开发者提供了更强大的工具来构建高性能、可维护的UI。通过理解这些变化和最佳实践,开发者可以充分利用React的强大能力,同时避免常见的陷阱。

相关推荐
Slow菜鸟1 小时前
ES5 vs ES6:JavaScript 演进之路
前端·javascript·es6
小冯的编程学习之路1 小时前
【前端基础】:HTML
前端·css·前端框架·html·postman
Jiaberrr2 小时前
Vue 3 中搭建菜单权限配置界面的详细指南
前端·javascript·vue.js·elementui
懒大王95272 小时前
uniapp+Vue3 组件之间的传值方法
前端·javascript·uni-app
烛阴3 小时前
秒懂 JSON:JavaScript JSON 方法详解,让你轻松驾驭数据交互!
前端·javascript
拉不动的猪3 小时前
刷刷题31(vue实际项目问题)
前端·javascript·面试
zeijiershuai3 小时前
Ajax-入门、axios请求方式、async、await、Vue生命周期
前端·javascript·ajax
恋猫de小郭3 小时前
Flutter 小技巧之通过 MediaQuery 优化 App 性能
android·前端·flutter
只会写Bug的程序员3 小时前
面试之《webpack从输入到输出经历了什么》
前端·面试·webpack
拉不动的猪3 小时前
刷刷题30(vue3常规面试题)
前端·javascript·面试