Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
136 views
in Technique[技术] by (71.8m points)

javascript - How do i rerender my screen after deletion from list?

Hello I've been looking through several threads on stackoverflow but I haven't been able to solve my problem. I have an app where you can save movies to a watchlist. On this specific screen I want to display a users watchlist and give them the ability to delete it from the list. Currently the function is indeed deleting the movie from the list and removing it from firebase but i can't get my screen to rerender to visually represent the deletion.

This is the code right now:


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>
  );
}


I've been trying to play around with useStates and I think the answer is in that direction but I just can't seem to get it to work anyway. Any help would be appreciated!

question from:https://stackoverflow.com/questions/65882793/how-do-i-rerender-my-screen-after-deletion-from-list

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are a few lines in your code that show a misunderstand of React state. You have a value let movieWatchlist: any[] = []; that you reassign in convertDataToArray() and mutate in handleOnPressDelete. That's just not how we do things in React and it's not going to trigger updates properly. movieWatchlist either needs to be a stateful variable created with useState.

Do the movies passed in through props change? If they do, then you don't need to store them in state here. You could just return an array from convertDataToArray() rather than setting a variable and returning void.

To be honest it's really not clear what convertDataToArray is even doing as it seems like newMovie is either the same or a subset of the original movie object. If the point is to remove the other properties aside from these four, that's not actually needed. If the prop movies is already an array, just delete this whole function and use movies directly. If it's a keyed object, use Object.values(movies) to get it as an array.

I'm thoroughly confused as to what we are getting from props and what we are getting from firebase. It seems like we would want to update the snapshot state after deletion, but you only run your useEffect once on mount.

You may still have errors, but this code should be an improvement:

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>
  );
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...