首页 > 解决方案 > 如何在 React Native 中从孙子到祖父母,然后再回到祖父母的孩子

问题描述

我是 React 的新手,所以我希望我能正确解决这个问题。首先,我有一个名为SearchLocationsScreen的屏幕。在该屏幕内,我有一个名为Map的组件,在Map内部,我有一个名为LocationMarker的自定义标记组件。在与Map组件相同的层级上,我有一个名为 CheckinModal 的自定义ModalBox。这是一个粗略的图表来帮助:

在此处输入图像描述

SearchLocationsScreen中,我从 API 调用中获取位置信息。然后我将这些位置传递给我的地图组件。在我的Map组件中,我将标记的信息传递给自定义LocationMarker类并填充地图。

目标是按下标记并让CheckinModal从底部弹出并使用来自按下的特定标记的信息填充它。为此,我使用useRef钩子和forwardRef钩子将对模态的引用向下传递给LocationMarker类。我在这里打电话ref.current.open(),模态按预期打开。

问题是我无法找到一种方法来从标记传递位置信息,将层次结构备份到屏幕并向下到模态以使用相关信息填充模态。有谁知道如何实现这一目标?我将下面的代码发布到我的屏幕、地图组件和标记组件(不包括样式)。在此先感谢您的帮助。

SearchLocationsScreen.js

const SearchLocationsScreen = ({isFocused, navigation}) => {

    const {updateLocation} = useContext(CurrentLocationContext);

    // hooks
    const callback = useCallback((location) => {
        updateLocation(location)
    }, []);
    const [err] = useCurrentLocation(isFocused, callback);
    const [businessLocations] = useGetLocations();

    const modalRef = useRef(null);

    let locations = [];

    if (businessLocations) {
        for (let x = 0; x < businessLocations.length; x++) {
            locations.push({
                ...businessLocations[x],
                latitude: businessLocations[x].lat,
                longitude: businessLocations[x].lng,
                key: x,
            })
        }
    }

    return (
        <View style={{flex: 1}}>

            <Map markers={locations} ref={modalRef}/>

            <SearchBar style={styles.searchBarStyle}/>

            {err ? <View style={styles.errorContainer}><Text
                style={styles.errorMessage}>{err.message}</Text></View> : null}

            <CheckinModal
                ref={modalRef}
            />

        </View>
    );
};

地图.js

    const Map = ({markers}, ref) => {

        const {state: {currentLocation}} = useContext(Context);

        // todo figure out these error situations
        if (!currentLocation) {
            return (
                <View style={{flex: 1}}>
                    <MapView
                        style={styles.map}
                        provider={PROVIDER_GOOGLE}
                        initialRegion={{
                            latitude: 27.848680,
                            longitude: -82.646560,
                            latitudeDelta: regions.latDelta,
                            longitudeDelta: regions.longDelta
                        }}
                    />

                    <ActivityIndicator size='large' style={styles.indicator} />
                </View>
            )
        }

        return (

            <MapView
                style={styles.map}
                provider={PROVIDER_GOOGLE}
                initialRegion={{
                    ...currentLocation.coords,
                    latitudeDelta: regions.latDelta,
                    longitudeDelta: regions.longDelta
                }}
                showsUserLocation
                >

                { markers ? markers.map((marker, index) => {
                    return <LocationMarker
                        ref={ref}  // passing the ref down to the markers
                        key={index}
                        coordinate={marker}
                        title={marker.company}
                        waitTime={ marker.wait ? `${marker.wait} minutes` : 'Open'}
                    />;
                }) : null}

            </MapView>
        )
    };

    const forwardMap = React.forwardRef(Map);

    export default forwardMap;

LocationMarker.js

const LocationMarker = ({company, coordinate, title, waitTime, onShowModal}, ref) => {
    return (
        <View>
            <Marker
                coordinate={coordinate}
                title={title}
                onPress={() => {
                    console.log(ref);
                    ref.current.open();
                }}
            >
                <Image
                    source={require('../../assets/marker2.png')}
                    style={styles.locationMarker}/>
                <View style={styles.waitContainer}><Text style={styles.waitText}>{waitTime}</Text></View>
            </Marker>

        </View>
    )
};

const forwardMarker = React.forwardRef(LocationMarker);

export default forwardMarker;

标签: reactjsreact-nativereact-hooksreact-props

解决方案


如果我理解正确,我建议不要forwardRef使用 prop 从父级传递 ref ,而是ref将其作为简单的 prop 传递。当它到达嵌套组件(在您的情况下为LocationMarker)时,您可以分配它。这是一个简化版本:

const SearchLocationsScreen = props => {
    const marker_ref = useRef(null);
    const modal_ref = useRef(null);

    return (
        <View>
            <Map marker_ref={marker_ref} modal_ref={modal_ref} />
            <CheckinModal marker_ref={marker_ref} modal_ref={modal_ref} />
        </View>
    );
};

const Map = props => {
    const { marker_ref, modal_ref } = props;

    return <LocationMarker marker_ref={marker_ref} modal_ref={modal_ref} />;
};

const LocationMarker = props => {
    const { marker_ref, modal_ref } = props;

    return <div ref={marker_ref}  />;
};

const CheckinModal = props => {
    const { marker_ref, modal_ref } = props;

    return <div ref={modal_ref}  />;
};

当 ref 到达最后一个元素时,我们使用ref=. 请记住,这个最终元素必须是 JSX 元素,例如div,而不是组件。

为了避免通过中间的每个组件将这些道具从祖父母传递给孩子,您可以SearchLocationsScreen.


推荐阅读