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

React天气应用中如何让OnChange与OnKeyDown事件协同工作?

问题

开发对接OpenWeather API的天气应用,需求如下:

  • 搜索输入框在用户按下回车键后获取输入值
  • 保留onChange与onKeyDown事件

当前遇到的问题:

  • 用onChange获取值,onKeyDown调用searchLocation更新URL参数传位置给API,但按下回车后位置不更新
  • 移除部分逻辑会导致API被频繁调用
  • 尝试用全局布尔变量控制无效
  • 需要从更新后的URL中获取用户输入的位置信息

.tsx核心逻辑代码

const searchParams = useSearchParams();
const pathName = usePathname();
const { replace } = useRouter();
globalThis.keyPressed = false
let location = '';

function setLocation(lct: string, evt: ChangeEvent<HTMLInputElement>){
    evt.preventDefault();
    
    if(globalThis.keyPressed){ 
      const selectedLocation = searchParams.get("location");
      
      replace(`?${new URLSearchParams({location: lct})}`)

      ApiHandler(location);
    }
}

function searchLocation(evt: React.KeyboardEvent<HTMLInputElement>){
   evt.preventDefault();
        
    globalThis.keyPressed = true;
    
    const params = new URLSearchParams(searchParams);

    if (location != ''){
        params.set('query', location);
    } else{
        params.delete('query');
    }
    replace(`${pathName}?${params.toString()}`);
}

// 目标输入框
<input
    value={typeof location === 'string' ? location : ''}
    onChange={event => {setLocation(event.target.value, event)}}
    onKeyDown={ event => {event.key === 'Enter' ? searchLocation(event) : null} }
    placeholder="Enter Location"
    type="text"
    defaultValue={searchParams.get('query')?.toString()}
/> 

.jsx接口处理代码

export default async function ApiHandler(location) {
  
  try{
    const data = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${location}&units=imperial&appid=${process.env.API_KEY}`
    );
  
    const res = await data.json();
    console.log(res.data);
    
  } catch (error){
      console.log("Error connecting to api");
      return new Response("Error in getting weather data", { status: 500 });
  }
}

.d.ts全局变量声明

declare global {
    var keyPressed: boolean
}

解决方案

问题根源

  1. 用let location = ''声明的普通变量非响应式,React无法追踪其变化,导致值更新后UI与逻辑不同步
  2. 全局变量keyPressed的控制逻辑混乱,onChange触发时keyPressed尚未被设为true,条件判断失效
  3. 输入框同时设置value和defaultValue引发冲突,非响应式变量无法正确同步输入值

修复步骤

  1. 改用useState管理输入值,确保响应式更新
  2. 去掉全局变量,直接在回车事件中处理URL更新与API调用
  3. 统一用状态值绑定输入框value,从URL参数初始化状态

修复后的代码

.tsx核心逻辑

import { useState, useEffect } from 'react';
import { useSearchParams, usePathname, useRouter } from 'next/navigation';
import ApiHandler from './ApiHandler';

export default function SearchInput() {
  const searchParams = useSearchParams();
  const pathName = usePathname();
  const { replace } = useRouter();
  // 用useState管理输入值,从URL参数初始化
  const [location, setLocation] = useState(searchParams.get('query') || '');

  // 监听URL参数变化,同步到输入框(页面刷新或其他地方修改URL时)
  useEffect(() => {
    const query = searchParams.get('query');
    if (query !== location) {
      setLocation(query || '');
    }
  }, [searchParams, location]);

  // 回车事件处理:更新URL + 调用API
  const handleKeyDown = (evt: React.KeyboardEvent<HTMLInputElement>) => {
    if (evt.key === 'Enter') {
      evt.preventDefault();
      const trimmedLocation = location.trim();
      if (!trimmedLocation) return;

      // 更新URL参数
      const params = new URLSearchParams(searchParams);
      params.set('query', trimmedLocation);
      replace(`${pathName}?${params.toString()}`);

      // 调用API
      ApiHandler(trimmedLocation);
    }
  };

  // 输入变化仅更新状态
  const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
    setLocation(evt.target.value);
  };

  return (
    <input
      value={location}
      onChange={handleChange}
      onKeyDown={handleKeyDown}
      placeholder="Enter Location"
      type="text"
    />
  );
}

调整ApiHandler(修正错误)

原代码中console.log(res.data)错误,OpenWeather响应无data属性,同时增加参数编码与错误处理:

export default async function ApiHandler(location) {
  try {
    const data = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(location)}&units=imperial&appid=${process.env.API_KEY}`
    );

    if (!data.ok) {
      throw new Error(`API请求失败,状态码:${data.status}`);
    }

    const res = await data.json();
    console.log(res);
    return res;

  } catch (error) {
    console.error("Error connecting to api:", error);
    throw error;
  }
}

关键改进点

  • 用useState确保输入值响应式,避免普通变量的同步问题
  • 回车事件直接处理URL更新与API调用,去掉冗余全局变量
  • useEffect监听URL参数,保证输入框与URL状态同步
  • 对输入值做trim()处理,避免无效请求
  • encodeURIComponent处理位置参数,防止特殊字符导致API请求失败
  • 修正ApiHandler的响应处理逻辑,正确捕获并抛出错误

内容的提问来源于stack exchange,提问作者Marco Antonio Martinez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:13:21