You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React计数器组件为何两次打印console.log?求解决方案

React组件重复打印问题排查与解决

问题描述

Small组件无论是首次创建还是点击+1按钮时,console.log都会输出两次,尝试用memo处理无效。

相关代码

App.js

import { useCounter } from "../Hooks/useCounter";
import { Small } from "./Small";

export const Memorize = () => {
  const {counter, increment} = useCounter(10)

  return(
    <>
      <Small value={counter}/>
      <button
        onClick={event => increment()}>
        +1
      </button>
    </>
  )
}

useCounter.js(计数器功能正常)

import { useState } from "react";

export const useCounter = (initialValue = 0) => {
  const [counter, setCounter] = useState(initialValue)

  const increment = (value = 1) => setCounter(counter + value)

  return {
    counter,
    increment,
    setCounter
  }
}

Small.js

export const Small = ({value}) => {
  console.log('Iam console log...');

  return (
    <small>{value}</small>
  )
}

现象

每次点击+1按钮,控制台输出:

Iam console log...
Iam console log...

解决方法

1. 移除React严格模式(开发环境)

这是最常见的触发原因。React 18的严格模式会在开发环境下强制触发两次组件渲染,目的是提前暴露潜在的副作用问题,生产环境不会有这个行为。

找到项目入口文件(通常是index.js),检查是否包裹了<React.StrictMode>,移除后重复打印问题会直接消失:

// index.js 修改后
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { Memorize } from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // 移除<React.StrictMode>包裹
  <Memorize />
);

2. 正确使用memo优化组件

若需要保留严格模式,同时避免组件在value不变时重复渲染,要正确导入并使用memo:

// Small.js 修改后
import { memo } from 'react';

export const Small = memo(({value}) => {
  console.log('Iam console log...');

  return (
    <small>{value}</small>
  )
})

注意:严格模式下的两次渲染是框架的检查机制,memo无法阻止这种场景下的重复打印,但能避免因value未变化导致的不必要渲染。

3. 优化useCounter的函数引用(可选)

当前useCounter中的increment函数每次都会重新创建,虽不直接导致Small重复渲染,但可以用useCallback优化,提升父组件性能:

// useCounter.js 修改后
import { useState, useCallback } from "react";

export const useCounter = (initialValue = 0) => {
  const [counter, setCounter] = useState(initialValue)

  const increment = useCallback((value = 1) => {
    setCounter(prev => prev + value); // 改用函数式更新,避免依赖counter
  }, []); // 空依赖数组,确保函数只创建一次

  return {
    counter,
    increment,
    setCounter
  }
}

内容的提问来源于stack exchange,提问作者Hector

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:02:05