我已经在这个问题上进行了一段时间的战斗,但我似乎不知道该如何解决。
在主屏幕上,我获取用户坐标和一系列电影院。 Cinemas数组包含每个电影院的坐标,我将其与用户坐标一起用于计算从用户到电影院的距离。
在CinemaContext中获取和存储电影院是可行的,但是一旦我运行了计算距离的函数,上下文中的电影院对象就为空。 距离计算会向数组中的每个电影院添加一个距离值,然后返回新的数组。
奇怪的是,当我尝试时,电影上下文对象为空。然后,如果我在CinemaContext或getUserCoordinates函数内部进行编辑,然后导航到电影院概览屏幕,那么电影院就在那儿并带有距离值。
必须具有加载顺序或异步功能,因为代码是“有效的”,但似乎并没有在正确的时间填充上下文或用空值覆盖上下文。
我应该补充一点,我在另一个屏幕上使用Cinemas数组,在这里可以像这样访问它:
const { state } = useContext(Context)
Home.js
import React, { useState, useEffect, useContext } from "react";
import { View, Text, StyleSheet, TouchableOpacity, StatusBar, ActivityIndicator } from "react-native";
import * as Location from 'expo-location';
import { Context } from "../context/CinemaContext";
const Home = ({ navigation }) => {
const [errorMsg, setErrorMsg] = useState(null);
const { state, updateCinemas, getCinemas } = useContext(Context)
// Fetch user coordinates and call updateCinemas with the coordinates and cinemas
const getUserCoordinates = async (cinemas) => {
try {
const granted = await Location.requestPermissionsAsync();
if (granted) {
let location = await Location.getCurrentPositionAsync({});
await updateCinemas(cinemas, location.coords.latitude, location.coords.longitude)
} else {
throw new Error("Location permission not granted");
}
} catch (e) {
setErrorMsg(e)
}
}
useEffect(() => {
if (state.cinemas.length === 0) {
getCinemas();
}
getUserCoordinates(state.cinemas);
}, []);
if (!state.cinemas) {
return <ActivityIndicator size="large" style={{ marginTop: 200 }} />
}
return ( Some views ..)
CinemaContext.js
import dataContext from "./DataContext";
import _ from "lodash";
import { computeDistance } from "../helpers/utils";
const cinemaReducer = (state, action) => {
switch (action.type) {
case "add_error":
return { ...state, errorMessage: action.payload };
case "get_cinemas":
return { ...state, cinemas: action.payload };
case "update_cinemas":
return { ...state, cinemas: action.payload };
default:
return state
}
};
const getCinemas = dispatch => async () => {
try {
const response = await fetch(
"url-to-cinemas-array",
{ mode: "no-cors" })
const cinemas = await response.json();
dispatch({
type: "get_cinemas",
payload: cinemas
});
} catch (err) {
dispatch({
type: "add_error",
payload: "Something went wrong with the cinemas"
})
}
}
const updateCinemas = (dispatch) => {
return async (cinemas, referenceLat, referenceLong) => {
const cinemasWithDistance = cinemas.map(cinema => {
return {
...cinema,
distance: computeDistance([cinema.geo.latitude, cinema.geo.longitude], [referenceLat, referenceLong]) // Calculate the distance
};
});
const orderedCinemas = _.orderBy(cinemasWithDistance, 'distance');
dispatch({ type: "update_cinemas", payload: orderedCinemas });
}
}
export const { Context, Provider } = dataContext(
cinemaReducer,
{ updateCinemas, getCinemas },
{ cinemas: [], errorMessage: '' }
);
DataContext.js
import React, { useReducer } from 'react';
export default (reducer, actions, defaultValue) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, defaultValue);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
};
App.js
import React from "react";
import RootStackNavigator from "./src/navigation/RootStackNavigator";
import { Provider } from "./src/context/CinemaContext";
export default function App() {
return (
<Provider>
<RootStackNavigator />
</Provider>
);
};
任何帮助将不胜感激! 预先感谢!
答案 0 :(得分:0)
我认为,当您调用class Backgrounds extends StatefulWidget {
@override
_BackgroundsState createState() => _BackgroundsState();
}
class _BackgroundsState extends State<Backgrounds> {
List<String> imagePath = [
'images/image1.png',
'images/image2.png',
'images/image3.png',
'images/image4.png',
'images/image5.png',
'images/image6.png',
'images/image7.png',
'images/image8.png',
'images/image9.png'
];
@override
Widget build(BuildContext context) {
return GridView.count(
scrollDirection: Axis.vertical,
crossAxisCount: 3,
children: List.generate(
9,
(index) => index == 0
? ToggleButtonWidget(
isFirst: true,
imagePath: imagePath[index],
)
: ToggleButtonWidget(
imagePath: imagePath[index],
),
),
);
}
}
class ToggleButtonWidget extends StatefulWidget {
final bool isFirst;
final String imagePath;
ToggleButtonWidget({this.isFirst = false, this.imagePath});
@override
_ToggleButtonWidgetState createState() => _ToggleButtonWidgetState();
}
class _ToggleButtonWidgetState extends State<ToggleButtonWidget> {
List<bool> _isSelected;
@override
void initState() {
_isSelected = [widget.isFirst ? true : false];
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
height: 100,
width: 107,
child: ToggleButtons(
children: [
Image.asset(widget.imagePath),
],
isSelected: _isSelected,
onPressed: (int index) {
setState(() {
_isSelected[0] = !_isSelected[0];
});
},
selectedBorderColor: Color(0xff2244C7),
borderWidth: 3,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
);
}
}
时state.cinemas
仍然为空,因此getUserCoordinates(state.cinemas);
动作将以一个空数组运行,覆盖"update_cinemas"
之前更新的电影院数组。您可以通过在"get_cinemas"
调用之前添加console.log('state.cinemas.length: ', state.cinemas.length);
来验证这一点。
对此,我认为一种解决方案是在依赖于getUserCoordinates
数组的单独getUserCoordinates
中调用useEffect
(这样每次state.cinemas
更改时它都会再次运行) :
state.cinemas