您好,我一直在查看有关 stackoverflow 的几个线程,但我一直无法解决我的问题。我有一个应用程序,您可以在其中将电影保存到监视列表。在这个特定的屏幕上,我想显示一个用户监视列表,并让他们能够从列表中删除它。目前该功能确实从列表中删除电影并将其从 firebase 中删除,但我无法让我的屏幕重新渲染以直观地表示删除。
这是现在的代码:
export default function MovieWatchlistTab(props: any) {
let { movies } = props;
let movieWatchlist: any[] = [];
const [watchlistSnapshot, setWatchlistSnapshot] = useState();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
useEffect(() => {
getWatchlistSnapshot();
}, []);
const getWatchlistSnapshot = async () => {
setWatchlistSnapshot(await watchlistRef.where("userId", "==", email).get());
};
const convertDataToArray = () => {
const convertedMovieList = [];
for (let movie in movies) {
let newMovie = {
backdrop: movies[movie].backdrop,
overview: movies[movie].overview,
release: movies[movie].release,
title: movies[movie].title,
};
convertedMovieList.push(newMovie);
}
movieWatchlist = convertedMovieList;
};
const renderMovieList = () => {
convertDataToArray();
return movieWatchlist.map((m) => {
const handleOnPressDelete = () => {
const documentRef = watchlistRef.doc(watchlistSnapshot.docs[0].id);
const FieldValue = firestore.FieldValue;
documentRef.set(
{
movies: {
[m.title]: FieldValue.delete(),
},
},
{ merge: true }
);
movieWatchlist.splice(
movieWatchlist.indexOf(m),
movieWatchlist.indexOf(m) + 1
);
console.log("movieWatchlist", movieWatchlist);
};
const swipeButtons = [
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
onPress: handleOnPressDelete,
},
];
return (
<Swipeout right={swipeButtons} backgroundColor={"#18181b"}>
<View key={m.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: m.backdrop,
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17,
}}
>
{m.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {m.release}
</Text>
</View>
</View>
</Swipeout>
);
});
};
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b",
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width,
}}
>
{renderMovieList()}
</ScrollView>
</View>
);
}
我一直在尝试使用 useStates,我认为答案是朝这个方向发展,但无论如何我似乎无法让它发挥作用。任何帮助将不胜感激!
答案 0 :(得分:1)
您的代码中有几行显示了对 React 状态的误解。您有一个值 let movieWatchlist: any[] = [];
,您在 convertDataToArray()
中重新分配并在 handleOnPressDelete
中改变。这不是我们在 React 中做事的方式,它不会正确触发更新。 movieWatchlist
要么需要是使用 useState
创建的有状态变量。
通过 movies
传入的 props
是否发生变化?如果是这样,那么您无需将它们存储在此处的 state
中。您可以只从 return
array
一个 convertDataToArray()
而不是设置变量并返回 void
。
老实说,现在还不清楚 convertDataToArray
在做什么,因为看起来 newMovie
与原始电影对象相同,或者是原始电影对象的子集。如果重点是删除除这四个属性之外的其他属性,那实际上并不需要。如果 prop movies
已经是一个数组,只需删除整个函数并直接使用 movies
。如果是键控对象,请使用 Object.values(movies)
将其作为数组获取。
对于我们从 props
获得什么以及我们从 firebase 获得什么,我感到非常困惑。看起来我们希望在删除后更新快照状态,但您在挂载时只运行一次 useEffect
。
你可能仍然有错误,但这段代码应该是一个改进:
interface Movie {
backdrop: string;
overview: string;
release: string;
title: string;
}
const MovieThumbnail = (props: Movie) => (
<View key={props.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: props.backdrop
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17
}}
>
{props.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {props.release}
</Text>
</View>
</View>
);
export default function MovieWatchlistTab() {
const [watchlistSnapshot, setWatchlistSnapshot] = useState<DocumentSnapshot>();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
const getWatchlistSnapshot = async () => {
const results = await watchlistRef.where("userId", "==", email).get();
setWatchlistSnapshot(results.docs[0]);
};
useEffect(() => {
getWatchlistSnapshot();
}, []);
const deleteMovie = async (title: string) => {
if ( ! watchlistSnapshot ) return;
const documentRef = watchlistRef.doc(watchlistSnapshot.id);
const FieldValue = firestore.FieldValue;
await documentRef.set(
{
movies: {
[title]: FieldValue.delete()
}
},
{ merge: true }
);
// reload watch list
getWatchlistSnapshot();
};
// is this right? I'm just guessing
const movies = ( watchlistSnapshot ? watchlistSnapshot.data().movies : []) as Movie[];
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b"
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width
}}
>
{movies.map((m) => (
<Swipeout
right={[
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
// need to pass the title to the delete handler
onPress: () => deleteMovie(m.title)
}
]}
backgroundColor={"#18181b"}
>
<MovieThumbnail {...m} />
</Swipeout>
))}
</ScrollView>
</View>
);
}