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

React中如何阻止输入框onChange触发组件重渲染

解决React组件输入框触发不必要重渲染的问题

问题描述

当前React组件中,输入框每输入一个字符触发onChange事件时,控制台都会打印console.log(result),说明每次输入都会导致整个Home组件重渲染。需要避免这种不必要的重渲染。

解决方案

方案1:拆分搜索表单为独立子组件

将输入相关逻辑抽成单独的子组件,让子组件自行管理输入状态,仅在提交时将城市名传递给父组件。这样输入时只有子组件重渲染,父组件Home不会触发重渲染,也就不会打印多余的result日志。

子组件代码(SearchForm.jsx)

const SearchForm = ({ onSubmit }) => {
  const [inputCity, setInputCity] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    if (inputCity.trim()) {
      onSubmit(inputCity);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        className="home__input"
        value={inputCity}
        onChange={(e) => setInputCity(e.target.value)}
        placeholder="输入城市名"
      />
      <button type="submit" className="weather__button">
        Search
      </button>
    </form>
  );
};

export default SearchForm;

修改后的Home组件代码

import "./home.css";
import SearchForm from "./SearchForm";
import { useState, useEffect } from "react";

const Home = () => {
  const [city, setCity] = useState("kampala");
  const [result, setResult] = useState(null);

  const fetchApi = async (city) => {
    const data = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=你的API密钥`
    ).then((res) => res.json())
    .then((data) => setResult(data));
  };

  useEffect(() => {
    fetchApi(city);
    console.log("heyy");
  }, []);

  const handleSearchSubmit = async (inputCity) => {
    setCity(inputCity);
    await fetchApi(inputCity);
  };

  if(result === null) {
    return <p>Loading</p>
  }

  console.log(result); // 现在仅在提交搜索或result变化时打印

  return (
    <div className="home__container">
      <div className="home__img">
        <div className="home__hero__info">
          <div>
            <h1>26 C</h1>
          </div>
          <div>
            <h3>Kampala</h3>
            <p>31 - October - 2022</p>
          </div>
          <div>
            <p>Suuny</p>
          </div>
        </div>
      </div>
      <div className="home__details">
        <div className="weather__div">
          <SearchForm onSubmit={handleSearchSubmit} />
          <div className="weather__ul">
            <ul>
              <li>Kampala</li>
              <li>Nairobi</li>
              <li>Dodoma</li>
            </ul>
          </div>
          <hr />
        </div>
        <div className="weather__div">
          <h4 className="h4">Weather Conditions</h4>
          <div>
            <span className="weather__details">
              <h4>Cloudy</h4>
              <h3>{result.clouds.all}%</h3>
            </span>
            <span className="weather__details">
              <h4>Humidity</h4>
              {/* <h3>{result.main.humidity}%</h3> */}
            </span>
            <span className="weather__details">
              <h4>Wind</h4>
              {/* <h3>{wind.speed}</h3> */}
            </span>
            <span className="weather__details">
              <h4>Rain</h4>
              <h3>23%</h3>
            </span>
          </div>
          <hr />
        </div>
      </div>
    </div>
  );
};

export default Home;

方案2:使用useRef管理输入值(不拆分组件)

如果不想拆分组件,可以用useRef存储输入框的值,输入时不会触发组件状态更新,也就不会导致重渲染。仅在点击搜索按钮时,才更新city状态并触发API请求。

修改后的Home组件代码

import "./home.css";
import { useState, useEffect, useRef } from "react";

const Home = () => {
  const [city, setCity] = useState("kampala");
  const [result, setResult] = useState(null);
  const inputRef = useRef(null); // 创建ref存储输入框

  const fetchApi = async (city) => {
    const data = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=你的API密钥`
    ).then((res) => res.json())
    .then((data) => setResult(data));
  };

  useEffect(() => {
    fetchApi(city);
    console.log("heyy");
  }, []);

  const handleSubmit = async (e) => {
    e.preventDefault();
    const inputCity = inputRef.current.value.trim();
    if (inputCity) {
      setCity(inputCity);
      await fetchApi(inputCity);
    }
  };

  if(result === null) {
    return <p>Loading</p>
  }

  console.log(result); // 仅在提交搜索或result变化时打印

  return (
    <div className="home__container">
      <div className="home__img">
        <div className="home__hero__info">
          <div>
            <h1>26 C</h1>
          </div>
          <div>
            <h3>Kampala</h3>
            <p>31 - October - 2022</p>
          </div>
          <div>
            <p>Suuny</p>
          </div>
        </div>
      </div>
      <div className="home__details">
        <div className="weather__div">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              className="home__input"
              ref={inputRef} // 绑定ref
              defaultValue={city} // 设置默认值
            />
            <button type="submit" className="weather__button">
              Search
            </button>
          </form>
          <div className="weather__ul">
            <ul>
              <li>Kampala</li>
              <li>Nairobi</li>
              <li>Dodoma</li>
            </ul>
          </div>
          <hr />
        </div>
        <div className="weather__div">
          <h4 className="h4">Weather Conditions</h4>
          <div>
            <span className="weather__details">
              <h4>Cloudy</h4>
              <h3>{result.clouds.all}%</h3>
            </span>
            <span className="weather__details">
              <h4>Humidity</h4>
              {/* <h3>{result.main.humidity}%</h3> */}
            </span>
            <span className="weather__details">
              <h4>Wind</h4>
              {/* <h3>{wind.speed}</h3> */}
            </span>
            <span className="weather__details">
              <h4>Rain</h4>
              <h3>23%</h3>
            </span>
          </div>
          <hr />
        </div>
      </div>
    </div>
  );
};

export default Home;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 12:15:32