【问题标题】:How do i rerender my screen after deletion from list?从列表中删除后如何重新渲染我的屏幕?
【发布时间】:2021-04-29 03:24:12
【问题描述】:

您好,我一直在查看 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,我认为答案是朝着这个方向,但我似乎无法让它发挥作用。任何帮助将不胜感激!

【问题讨论】:

  • 在从 Firebase 中删除之前,从数组中过滤项目并显示过滤后的数组

标签: javascript typescript firebase react-native


【解决方案1】:

您的代码中有几行表明对 React 状态的误解。你有一个值let movieWatchlist: any[] = [];,你在convertDataToArray() 中重新分配并在handleOnPressDelete 中变异。这不是我们在 React 中做事的方式,它不会正确触发更新。 movieWatchlist 必须是使用useState 创建的有状态变量。

通过props 传入的movies 是否改变?如果他们这样做,那么您不需要将它们存储在 state 这里。您可以只使用 convertDataToArray() 中的 returnarray,而不是设置变量并返回 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>
  );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-23
    • 2021-09-28
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多