Next.js跨组件共享数据与状态实现方法咨询
解决方案
你遇到的是React兄弟组件共享状态的典型场景,不需要引入额外复杂库,用状态提升的原生React方案就能实现:把两个组件都需要依赖的「当前查询城市」状态,放到Search和CardList共同的父组件中管理,再通过props分别向两个子组件传递状态、更新状态的回调即可。
具体实现步骤
1. 改造共同父组件
假设你两个组件都挂载在页面级父组件(比如Home.tsx/WeatherApp.tsx)中,在这里定义共享的城市状态,以及更新城市的方法:
import { useState } from 'react'; import { Search } from './Search/Search'; import { CardList } from './CardList/CardList'; export const WeatherApp = () => { // 共享状态:当前要查询的城市,默认值设为London兼容原有逻辑 const [currentCity, setCurrentCity] = useState('London'); return ( <div> {/* 把更新城市的回调传给Search组件 */} <Search onSubmitCity={setCurrentCity} /> {/* 把当前城市传给CardList组件用来拉取数据 */} <CardList city={currentCity} /> </div> ) }
2. 改造Search组件
输入框的临时输入值依然存在组件内部即可,接收父组件传入的提交回调,用户点击搜索按钮时触发回调,把输入的城市名传回父组件:
import { SearchProps } from "./Search.props"; import styles from "./Search.module.css"; import cn from 'classnames'; import { Input } from "../Input/Input"; import { Button } from "../Button/Button"; import { useState } from "react"; import GlassIcon from './glass.svg'; import { cookies } from "../../libs/setCookie"; // 扩展props类型,新增提交城市的回调定义 interface SearchExtendedProps extends SearchProps { onSubmitCity: (city: string) => void } export const Search = ({ className, onSubmitCity, ...props }: SearchExtendedProps): JSX.Element => { const [inputValue, setInputValue] = useState<string>(""); const handleOnClick = () => { // 输入为空时不触发查询 if (!inputValue.trim()) return; // 调用父组件传入的回调,把输入的城市传回父组件 onSubmitCity(inputValue.trim()); setInputValue(""); // 可选:提交后清空输入框 } const handleOnChange = (event) => { setInputValue(event.target.value); } return ( <div className={cn(className, styles.search)} {...props} > <Button appearance="ghost" className={styles.button} onClick={handleOnClick} > <GlassIcon /> </Button> <Input className={styles.input} placeholder="Search location here" value={inputValue} onChange={handleOnChange} // 可选:支持回车键直接触发搜索 onKeyDown={(e) => e.key === 'Enter' && handleOnClick()} /> </div> ) };
如果你需要保留之前的搜索城市列表citiesList,把这个状态也提升到父组件管理即可,逻辑和当前城市状态一致。
3. 改造CardList组件
接收父组件传入的城市参数,替换原来硬编码的London,同时把城市加到useEffect的依赖数组里,城市变化时自动重新拉取对应城市的天气数据:
import { CardListProps } from "./CardList.props"; import styles from "./CardList.module.css"; import React, { useState, useEffect } from 'react'; import { Card } from "../Card/Card"; import { API_KEY } from './settings'; // 扩展props类型,接收传入的城市参数 interface CardListExtendedProps extends CardListProps { city: string } export const CardList = ({ children, city, ...props }: CardListExtendedProps): JSX.Element => { const [data, setData] = useState(null); useEffect(() => { // 用传入的city替换硬编码的London,加encodeURIComponent处理特殊字符 fetch(`https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(city)}&appid=${API_KEY}&units=metric`) .then(res => res.json()) .then(setData) .catch(err => console.error('获取天气数据失败:', err)); }, [city]); // 把city加入依赖,城市变化就自动重新发请求 if (!data) return null; const { name, weather, main, wind, clouds } = data; const { description, icon } = weather[0]; const { temp, humidity, feels_like, pressure } = main; const { speed } = wind; const { all } = clouds; return ( <div className={styles.CardList} {...props} > <Card name="Wind Speed" info={parseFloat(speed.toFixed(2))+'km/h'}></Card> <Card name="Clouds" info={all + '%'}></Card> <Card name="Pressure" info={pressure + ' hpa'}></Card> <Card name="Humidity" info={humidity + '%'}></Card> </div> ) };
后续扩展说明
如果后续组件嵌套层级变深,靠props一层层传状态太繁琐,可以再按需升级方案:
- 跨层级共享少量全局状态用React内置的
Context API即可 - 轻量全局状态管理可以选Zustand、Jotai这类库,代码侵入性很低
- 涉及大量接口缓存、异步状态管理可以考虑React Query、RTK Query这类方案
当前需求用状态提升完全足够,代码改动最小也最好维护。
内容的提问来源于stack exchange,提问作者user17880509
相关产品推荐
相关产品推荐

