You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中更新观影状态后,如何让FlatList正确重新渲染?

问题:切换观影列表状态时FlatList无法正确更新

我需要实现一个切换开关,在「To Watch」和「Watched」预约列表之间切换。更新「To Watch」列表中的电影后,希望FlatList重新渲染,该电影不再出现在此列表(已移至「Watched」列表);切换到「Watched」列表时能看到该电影,反向操作同理。但当前代码无法正常工作,以下是我的代码:

const WatchList = () => {

  const uid = auth.currentUser.uid;
  const docRef = doc(db, 'users', uid);
  const [user, setUser] = useState({});
  const [watched, setWatched] = useState(true);
  const [text, setText] = useState('To watch');
  const [filteredBookings, setFilteredBookings] = useState(bookings);

  const bookingsRef = collection(db, "booking"); // imamo ref ka bazi

  const [bookings, setBookings] = useState({});
   useEffect(() => {
    getUser();
    getBookings();
  },[])

  const getUser = async () => {
    const snap = await getDoc(docRef)
    setUser({user, ...snap.data()})
  }

  const getBookings = async () =>{
    const q = query(bookingsRef, where("users","array-contains",auth.currentUser.uid));
      const unsubscribe = onSnapshot(q, (querySnapshot) => {
        const a = [];
        querySnapshot.forEach((doc) => {            
        a.push(doc.data());
      });
      setBookings(querySnapshot.docs);
    });
  }

  const toggleSwitch = () =>{
    if(!watched){
      setFilteredBookings(bookings.filter(function(item){
        return item.data().watched == true;
      }))
      setText('Watched');
    } else {
      setText('To watch');
      setFilteredBookings(bookings.filter(function(item){
        return item.data().watched == false;
      }))
    }
    setWatched(previousState => !previousState);
  }

  const updateBooking = async(id) => {
    try {
      await setDoc(doc(db, 'booking', id), {
        watched: true
      }, {merge: true})
    }
    catch(e) {
      console.log(e)
    }
  }

  const updateBooking1 = async(id) => {
    try {
      await setDoc(doc(db, 'booking', id), {
        watched: false
      }, {merge: true})
    }
    catch(e) {
      console.log(e)
    }
  }

  const deleteBooking = async(id) => {
    try {
      await deleteDoc(doc(db, 'booking', id));
    }
    catch(e) {
      console.log(e)
    }
  }

  useEffect(() => {
    const resultOfFiltering = bookings
    setFilteredBookings(resultOfFiltering)
  }, [bookings])

  return (
    <View>
      <View>
        <Text>{text}</Text>
        <Switch 
          value = {watched}
        />
      </View>
  
  <FlatList
    data = {filteredBookings}

    renderItem  = {({item}) => (
      <View>
      <View>
        <Text>{item.data().movie}</Text>
        <Text>{item.data().day} - {item.data().showtime}</Text>
      </View>
      <View>
        {item.data().watched == true ? (
            <TouchableOpacity style = {styles.delete} onPress = {() => {updateBookings(item.id); setFilteredBookings();}}>
            <Image source={require('../assets/watched.png')}/>
            </TouchableOpacity>
        ) : (
        <TouchableOpacity onPress = {() => {updateBookings1(item.id); setFilteredBookings();}}>
        <Image source={require('../assets/towatch.png')}/>
        </TouchableOpacity>)}

        <TouchableOpacity onPress = {() => {deleteBooking(item.id); setFilteredBookings();}}>
          <Image source={require('../assets/remove.png')}/>
        </TouchableOpacity>
      </View>
      </View>
    )}
  />
      </View>
  )
}

export default WatchList

问题排查与修复方案

1. 核心错误点

  • 函数名拼写错误:渲染代码中调用的updateBookings/updateBookings1,实际定义的函数是updateBooking/updateBooking1,点击后无响应
  • Switch未绑定切换逻辑:Switch组件缺少onValueChange属性,点击开关不会触发状态切换
  • 过滤逻辑冲突:监听bookings变化的useEffect会直接覆盖过滤后的列表,导致切换开关后数据被重置
  • 状态初始化错误:filteredBookings初始值设为未定义的bookings,应该初始化为空数组[]
  • 无效状态更新:点击按钮时调用setFilteredBookings()会把数据设为undefined,无需手动触发,Firestore的onSnapshot会自动更新数据

2. 修复后的完整代码

const WatchList = () => {

  const uid = auth.currentUser.uid;
  const docRef = doc(db, 'users', uid);
  const [user, setUser] = useState({});
  const [watched, setWatched] = useState(true);
  const [text, setText] = useState('To watch');
  const [filteredBookings, setFilteredBookings] = useState([]);

  const bookingsRef = collection(db, "booking");

  const [bookings, setBookings] = useState([]);
  
  useEffect(() => {
    getUser();
    const unsubscribe = getBookings();
    // 清理Firestore订阅,避免内存泄漏
    return unsubscribe;
  },[])

  const getUser = async () => {
    const snap = await getDoc(docRef)
    setUser({...user, ...snap.data()})
  }

  const getBookings = () =>{
    const q = query(bookingsRef, where("users","array-contains",auth.currentUser.uid));
    return onSnapshot(q, (querySnapshot) => {
      setBookings(querySnapshot.docs);
    });
  }

  const toggleSwitch = () =>{
    const newWatchedState = !watched;
    setWatched(newWatchedState);
    setText(newWatchedState ? 'To watch' : 'Watched');
  }

  const updateBooking = async(id) => {
    try {
      await setDoc(doc(db, 'booking', id), {
        watched: true
      }, {merge: true})
    }
    catch(e) {
      console.log(e)
    }
  }

  const updateBooking1 = async(id) => {
    try {
      await setDoc(doc(db, 'booking', id), {
        watched: false
      }, {merge: true})
    }
    catch(e) {
      console.log(e)
    }
  }

  const deleteBooking = async(id) => {
    try {
      await deleteDoc(doc(db, 'booking', id));
    }
    catch(e) {
      console.log(e)
    }
  }

  // 根据当前切换状态自动过滤列表
  useEffect(() => {
    if (!bookings.length) return;
    const filtered = bookings.filter(item => {
      return item.data().watched === !watched;
    });
    setFilteredBookings(filtered);
  }, [bookings, watched])

  return (
    <View>
      <View>
        <Text>{text}</Text>
        <Switch 
          value={watched}
          onValueChange={toggleSwitch}
        />
      </View>
  
      <FlatList
        data={filteredBookings}
        keyExtractor={(item) => item.id}
        renderItem={({item}) => (
          <View>
            <View>
              <Text>{item.data().movie}</Text>
              <Text>{item.data().day} - {item.data().showtime}</Text>
            </View>
            <View>
              {item.data().watched === true ? (
                <TouchableOpacity style={styles.delete} onPress={() => updateBooking(item.id)}>
                  <Image source={require('../assets/watched.png')}/>
                </TouchableOpacity>
              ) : (
                <TouchableOpacity onPress={() => updateBooking1(item.id)}>
                  <Image source={require('../assets/towatch.png')}/>
                </TouchableOpacity>
              )}

              <TouchableOpacity onPress={() => deleteBooking(item.id)}>
                <Image source={require('../assets/remove.png')}/>
              </TouchableOpacity>
            </View>
          </View>
        )}
      />
    </View>
  )
}

export default WatchList

3. 额外优化点

  • 添加keyExtractor给FlatList,避免React Native渲染警告
  • 修正getUser中的状态更新语法,确保正确合并用户数据
  • 在getBookings中返回订阅清理函数,防止组件卸载后内存泄漏

内容的提问来源于stack exchange,提问作者Mihailo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:20:29