我是React的新手,所以我希望我能正确解决这个问题。首先,我有一个名为SearchLocationsScreen的屏幕。在该屏幕内,我有一个名为Map的组件,在Map内有一个名为LocationMarker的自定义标记组件。在与Map组件相同的层次结构级别上,我有一个名为CheckinModal的自定义ModalBox。这是一个粗略的图表可以帮助您:
In SearchLocationsScreen I am getting the location info from an API call. Then I pass those locations down to my Map component. Inside my Map component I pass the information for the markers down to the custom LocationMarker class and populate the map.
The goal is to press on a marker and have the CheckinModal pop up from the bottom and populate it with info from the particular marker that was pressed. To do this, I use the useRef hook and forwardRef hook to pass a reference to the modal down to the LocationMarker class. Here I call ref.current.open()
and the modal opens as expected.
The problem is that I can't figure out a way to pass the location info from the marker, back up the hierarchy to the screen and down to the modal to populate the modal with relevant info. Does anyone know how to achieve this? I'm posting the code below to my screen, map component and marker component (styles not included). Thanks in advance for your help.
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>
);
};
Map.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;
I figured it out with the help of Alvaro's comment to my main post.
Here is what I did. First, I moved the code that generates the LocationMarkers to the SearchLocationsScreen. I was already accessing the locations needed for those markers on that screen anyway (originally I was then passing those locations down to the Map component and creating them there). In the SearchLocationsScreen I loop through all the locations to generate the LocationMarkers, adding a callback which uses a useReducer hook to store the modal's state. Since they are both on the same level, I can populate the fields for the modal with the correct data from the reducer's state. That callback is passed down to the LocationMarkers. Then in the LocationMarker onPress我调用此方法。一切正常。这是更新的代码:
SearchLocationsScreen
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,
})
}
}
const modalReducer = (state, action) => {
console.log("payload: ", action.payload);
switch (action.type) {
case 'show_modal':
return {...state,
companyName: action.payload.companyName,
companyAddress: action.payload.companyAddress,
waitTime: action.payload.waitTime
};
default:
return state;
}
};
const [modalState, dispatch] = useReducer(modalReducer, {
companyName: "Company Name",
companyAddress: "123 Elm St",
waitTime: 0
});
const createMarkers = () => {
let result = [];
if (locations) {
for (let i = 0; i < locations.length; i++) {
result.push(
<LocationMarker
key={i}
id={i}
coordinate={locations[i]}
title={locations[i].company}
waitTime={locations[i].wait ? `${locations[i].wait} minutes` : 'Closed'}
onShowModal={() => {
dispatch({
type: 'show_modal', payload: {
companyName: locations[i].company,
companyAddress: locations[i].address,
waitTime: locations[i].wait,
}
});
modalRef.current.open();
}}
/>
)
}
}
return result;
};
return (
<View style={{flex: 1}}>
<Map markers={createMarkers()}/>
{/*<Map ref={modalRef} markers={...createMarkers()} />*/}
<SearchBar style={styles.searchBarStyle}/>
{err ? <View style={styles.errorContainer}><Text
style={styles.errorMessage}>{err.message}</Text></View> : null}
<CheckinModal
ref={modalRef}
businessName={modalState.companyName}
address={modalState.companyAddress}
waitTime={modalState.waitTime}
/>
</View>
);
};
地图
const Map = ({markers}, ref) => {
const {state: {currentLocation}} = useContext(Context);
return (
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
initialRegion={{
...currentLocation.coords,
latitudeDelta: regions.latDelta,
longitudeDelta: regions.longDelta
}}
showsUserLocation
>
{markers ? markers.map((marker, index) => {
return marker;
}): null}
</MapView>
)
};
export default Map;
检入模式
const CheckinModal = ({businessName, address, waitTime}, ref) => {
return (
<ModalBox
style={styles.modal}
position={'bottom'}
backdrop={true}
ref={ref}
>
<Text>Store Name: {businessName}</Text>
<Text>Store Address: {address}</Text>
<Text>Wait time: {waitTime} minutes</Text>
</ModalBox>
)
};
const forwardModal = React.forwardRef(CheckinModal);
export default forwardModal;
LocationMarker
const LocationMarker = (props) => {
return (
<View>
<Marker
coordinate={props.coordinate}
title={props.title}
id={props.id}
onPress={() => {
props.onShowModal();
}}
>
<Image
source={require('../../assets/marker2.png')}
style={styles.locationMarker}/>
<View style={styles.waitContainer}>
<Text style={styles.waitText}>{props.waitTime}</Text>
</View>
</Marker>
</View>
)
};
export default LocationMarker;
有了这个新代码,我不必转发太多引用,而只需转发给CheckinModal即可。
如果有人有任何问题,请将其发布在此答案下方,我将尝试尽快回答。感谢大家的帮助。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句