React Hooks实现兄弟组件传值的方案(不使用Context)
React 不使用Context实现兄弟组件传值的方案
两个兄弟组件间传值且不使用Context时,最直接的方案是状态提升,这也是React官方推荐的同层级组件基础通信方案,核心逻辑是把两个组件共享的状态提取到它们共同的父组件中管理,再通过props分别向子组件传递需要的值和修改方法。
实现步骤
第一步:修改共同父组件(即你放置两个组件的首页组件)
将原本放在SearchBar内部的city状态提取到父组件统一维护:
// 示例为首页组件,比如Home.js import { useState } from 'react' import { SearchBar } from './SearchBar' import { ForecastButtons } from './ForecastButtons' export const Home = () => { // 公共状态:选中的城市 const [selectedCity, setSelectedCity] = useState('') return ( <div className="home-container"> {/* 给SearchBar传递修改城市的方法 */} <SearchBar onCitySelect={setSelectedCity} /> {/* 给ForecastButtons传递选中的城市值 */} <ForecastButtons city={selectedCity} /> </div> ) }
第二步:修改SearchBar组件
移除内部维护的city状态,改为调用父组件传入的方法更新公共状态:
export const SearchBar = ({ onCitySelect }) => { const [error, setError] = useState(null) const [loading, setLoading] = useState(true) const [cityList, setCityList] = useState(null) const handleOnSearch = (string, cityList) => { if(string.length >= 3) { const options = { method: `GET`, }; fetch(`/api/cityList?city=${string}`, options) .then((response) => { if(response.ok){ return response.json().then(setCityList) } throw new Error('Api is not available') }) .catch(error => { console.error('Error fetching data: ', error) setError(error) }) // 原代码此处缺少箭头函数,会导致方法直接提前执行 .finally(() => setLoading(false)) } } const allCities = cityList ? cityList : [] const handleOnSelect = (item) => { const city = item?.name // 调用父组件传入的方法更新公共状态 onCitySelect(city) } return( <div className="mb-6"> <label htmlFor="email" className="block text-sm font-medium text-gray-700"> Search city </label> <div className="grid grid-cols-5 gap-4"> <div className="col-span-3"> <div className="mt-1"> <ReactSearchAutocomplete id="city" name="city" type="text" items={allCities} fuseOptions={{ keys: ["name"] }} onSearch={handleOnSearch} onSelect={handleOnSelect} autoFocus autoComplete="off" className="py-3 px-4 block w-full shadow-sm focus:ring-blue-500 focus:border-blue-500 border-gray-300 rounded-md" /> </div> </div> <div className="col-span-2 mt-1"> <button className="mt-1 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" type='button' onClick={handleOnSelect}> Select City </button> </div> </div> </div> ) }
第三步:修改ForecastButtons组件
从props接收city值即可直接使用,同时修复原代码的几个逻辑问题:
export const ForecastButtons = ({ city }) => { const [payload, setPayload] = useState(null) // 原代码缺少这两个状态的定义,此处补充 const [error, setError] = useState(null) const [loading, setLoading] = useState(false) const fetchCityData = () => { // 未选城市时直接不执行请求 if(!city) return setLoading(true) const options = { method: `POST`, }; fetch(`/api/weather?city=${city}`, options) .then((response) => { if(response.ok){ return response.json().then(setPayload) } throw new Error('Api is not available') }) .catch(error => { console.error('Error fetching data: ', error) setError(error) }) // 原代码此处缺少箭头函数,会导致方法直接提前执行 .finally(() => setLoading(false)) } const location = payload?.location?.name; const currentTemp = payload?.current?.temp_c; return( <div className="sm:col-span-2"> <p className="block text-sm font-medium text-gray-700">Select forecast</p> {/* 原代码误用了只有form元素支持的onSubmit事件,改为button的onClick事件 */} <button onClick={fetchCityData} className="mt-1 bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded"> Today </button> <p key={payload?.location?.id} className='my-5'> { location ? `Current weather in ${location} is ${currentTemp} degrees ` : 'Please search for city to see current weather'} </p> </div> ) }
其他可选方案
如果你的组件嵌套层级很深,状态提升需要层层透传props比较繁琐,除了Context外还可以使用轻量级状态管理库(比如Zustand、Jotai)实现跨组件通信,但对于你当前的同级兄弟组件场景,状态提升是最简单无额外依赖的方案。
内容的提问来源于stack exchange,提问作者Katharina Schreiber
相关产品推荐
相关产品推荐

