React中如何将子组件的变量传递给父组件?
解决方案
方案1:通过共同父组件传递状态(最直接)
如果Banner和TabScreen有共同的父组件,这是最简单的实现方式:
- 父组件维护
bannerImageHeight状态 - 给
Banner传递回调函数,计算出imageHeight后更新父组件状态 - 将父组件的
bannerImageHeight作为props传给TabScreen
示例代码:
父组件
const ParentComponent = () => { const [bannerImageHeight, setBannerImageHeight] = useState(0); return ( <> <Banner onImageHeightChange={setBannerImageHeight} /> <TabScreen bannerHeight={bannerImageHeight} /> </> ); };
修改后的Banner组件
const Banner = ({ onImageHeightChange }) => { const [AdData, setAdData] = useState(); const [showBanner, setShowBanner] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); const imageHeight = MiscUtils.returnDefaultValueIfNotValid(0, AdData, 'fetchAds', 'ads', currentIndex, 'image', 'height'); // 高度变化时通知父组件 useEffect(() => { onImageHeightChange(imageHeight); }, [imageHeight, onImageHeightChange]); return ( <Image style={Styles.image} resizeMode={'stretch'} source={{uri: imageUrl}} height={imageHeight} /> ); }; export default Banner;
修改后的TabScreen组件
const TabScreen = ({ bannerHeight }) => { useEffect(() => { if(ref.current && !isScrollOnTop(ref.current.getCurrentScrollOffset())) { const offsetChange = isDisplayAdBannerVisible ? bannerHeight : -bannerHeight; ref.current.scrollToOffset(0, ref.current.getCurrentScrollOffset() + offsetChange, true); } }, [bannerHeight, isDisplayAdBannerVisible]); // 务必添加依赖项 // 其他组件代码... }; export default React.memo(TabScreen);
方案2:使用React Context(跨层级组件共享)
如果两个组件层级较深、没有直接共同父组件,用Context更合适:
- 创建存储banner高度的Context
- 在顶层组件用
Context.Provider包裹组件树 - 在Banner中更新Context值,TabScreen中订阅Context
示例代码:
创建BannerContext.js
import { createContext, useState, useContext } from 'react'; const BannerContext = createContext(); export const BannerProvider = ({ children }) => { const [bannerHeight, setBannerHeight] = useState(0); return ( <BannerContext.Provider value={{ bannerHeight, setBannerHeight }}> {children} </BannerContext.Provider> ); }; export const useBannerHeight = () => useContext(BannerContext);
修改Banner组件
import { useBannerHeight } from './BannerContext'; const Banner = () => { const [AdData, setAdData] = useState(); const [showBanner, setShowBanner] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); const { setBannerHeight } = useBannerHeight(); const imageHeight = MiscUtils.returnDefaultValueIfNotValid(0, AdData, 'fetchAds', 'ads', currentIndex, 'image', 'height'); useEffect(() => { setBannerHeight(imageHeight); }, [imageHeight, setBannerHeight]); return ( <Image style={Styles.image} resizeMode={'stretch'} source={{uri: imageUrl}} height={imageHeight} /> ); }; export default Banner;
修改TabScreen组件
import { useBannerHeight } from './BannerContext'; const TabScreen = () => { const { bannerHeight } = useBannerHeight(); useEffect(() => { if(ref.current && !isScrollOnTop(ref.current.getCurrentScrollOffset())) { const offsetChange = isDisplayAdBannerVisible ? bannerHeight : -bannerHeight; ref.current.scrollToOffset(0, ref.current.getCurrentScrollOffset() + offsetChange, true); } }, [bannerHeight, isDisplayAdBannerVisible]); // 其他组件代码... }; export default React.memo(TabScreen);
方案3:修复Redux实现(若仍想用Redux)
如果之前Redux没成功,大概率是状态更新或订阅环节出了问题,正确实现方式如下:
- 定义action类型和创建函数
// actions.js export const SET_BANNER_HEIGHT = 'SET_BANNER_HEIGHT'; export const setBannerHeight = (height) => ({ type: SET_BANNER_HEIGHT, payload: height });
- 更新reducer
// reducer.js import { SET_BANNER_HEIGHT } from './actions'; const initialState = { bannerHeight: 0 }; export const appReducer = (state = initialState, action) => { switch(action.type) { case SET_BANNER_HEIGHT: return { ...state, bannerHeight: action.payload }; default: return state; } };
- 在Banner中dispatch action
import { useDispatch } from 'react-redux'; import { setBannerHeight } from './actions'; const Banner = () => { const [AdData, setAdData] = useState(); const [showBanner, setShowBanner] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); const dispatch = useDispatch(); const imageHeight = MiscUtils.returnDefaultValueIfNotValid(0, AdData, 'fetchAds', 'ads', currentIndex, 'image', 'height'); useEffect(() => { dispatch(setBannerHeight(imageHeight)); }, [imageHeight, dispatch]); return ( <Image style={Styles.image} resizeMode={'stretch'} source={{uri: imageUrl}} height={imageHeight} /> ); }; export default Banner;
- 在TabScreen中用useSelector获取状态
import { useSelector } from 'react-redux'; const TabScreen = () => { const bannerHeight = useSelector(state => state.app.bannerHeight); useEffect(() => { if(ref.current && !isScrollOnTop(ref.current.getCurrentScrollOffset())) { const offsetChange = isDisplayAdBannerVisible ? bannerHeight : -bannerHeight; ref.current.scrollToOffset(0, ref.current.getCurrentScrollOffset() + offsetChange, true); } }, [bannerHeight, isDisplayAdBannerVisible]); // 其他组件代码... }; export default React.memo(TabScreen);
注意事项
- 所有方案都要确保
useEffect的依赖项完整,避免遗漏状态更新或不必要的重复渲染 - 若
imageHeight初始值为0,建议在TabScreen中添加 fallback 逻辑(比如默认用65)
内容的提问来源于stack exchange,提问作者Kumar Shivam
相关产品推荐
相关产品推荐

