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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 02:09:05