【问题标题】:Can't update state immediately?不能立即更新状态?
【发布时间】:2020-04-08 20:49:22
【问题描述】:

我有两个功能,第一个我得到所有订单,第二个我得到所有被拒绝的订单

所以在第一个函数中,我根据第二个函数状态更新状态 而且效果很好

但是当我从我的 Firebase 控制台中删除一个项目时,虽然我使用 on("value",()=>{}),但我无法立即看到更新

那我该如何处理呢?

警告

无法对未安装的组件执行 React 状态更新。这是 无操作,但它表明您的应用程序中存在内存泄漏。

结构数组

let ordersArray = [
   {"snapshotKey":"-awdawadsdwwd","username":"Joe"},
   {"snapshotKey":"-badsdasdad","username":"Annna"},
   {"snapshotKey":"-dasQwaddas","username":"lee"}
]

let rejectedOrders = ["-awdawadsdwwd","-dasQwaddas"] 

状态

this.state = {
      orders: [],
      rejectedOrders: [],
    };


componentDidMount() {
    try {
      this.getRejectedOrders();
      this.fetchOrders();
    } catch (err) {
      console.log('error', err);
    }
}

第一个函数

//Get all orders from DB

 fetchOrders = async () => {
    const {serviceName} = this.state;
    let uid = auth().currentUser.uid;
    const serviceStorage = await AsyncStorage.getItem('service');
    this.setState({serviceStorage});
    database()
      .ref(`Providers/CategoriesOrders/${serviceName || serviceStorage}`)
      .on('value', snapshot => {
        let orderArr = [];
        snapshot.forEach(childSnapshot => {
          orderArr.push({
            snapshotKey: childSnapshot.key,
            username: childSnapshot.val().username,
          });
        });
        this.setState(prevState => ({
          orders: orderArr.filter(
            order =>
              !prevState.rejectedOrders.some(key => order.snapshotKey === key),
          ),
          loading: false,
        }));
      });
  };

第二个功能

// get an array of rejected orders

  getRejectedOrders = () => {
    let uid = auth().currentUser.uid;
    const ref = database().ref(`Providers/users/${uid}`);
    ref.on('value', snapshot => {
      let rejectedOrders = snapshot.val().rejectedOrders;
      this.setState({rejectedOrders});
    });
  };

JSX

render(){
   return (
        <OrdersList
          data={this.state.orders}
          extraData={this.state}
          screenName="OrderHomeDetails"
        />
      );
}

组件

const OrdersList = props => {
  return (
    <View style={styles.container}>
      <FlatList
        showsVerticalScrollIndicator={false}
        data={props.data}
        extraData={props.extraData}
        ListEmptyComponent={<EmptyList />}
        keyExtractor={(item, index) => index.toString()}
        legacyImplementation={true}
        contentContainerStyle={{
          flexGrow: 1.2,
        }}
        renderItem={({item}) => {
          return (
            <TouchableOpacity
              onPress={() =>
                props.navigation.navigate(props.screenName, {
                  username: item.username,
                  snapshotKey: item.snapshotKey,
                })
              }
             >

                <View>
                  <Icon name="person" color="#AEACAC" size={20} />
                  <Text> {item.username}</Text>
                </View>

            </TouchableOpacity>
          );
        }}
      />
    </View>
  );
};

export default withNavigation(OrdersList);

我认为是 OrdersList 组件的问题,因为当我在每个函数“fetchOrders() /getRejectedOrders()”中的 setState 之后在回调中记录状态时,我得到了新的拒绝订单,而不是 fetchOrders() 中的订单

虽然

" 当我向被拒绝的订单数组添加/删除数据时,这意味着 getRejectedOrders() 只会改变,但 fetchOrders() 不是因为它与这些东西无关'它第一次得到所有订单然后根据某些东西和这些过滤它订单没变,为什么还要更新!”

编辑~1

fetchOrders = async () => {
    const {rejectedOrders, serviceName} = this.state;
    let uid = auth().currentUser.uid;
    const serviceStorage = await AsyncStorage.getItem('service');
    this.setState({serviceStorage});
    // await this.getRejectedOrders();
    database()
      .ref(`Providers/CategoriesOrders/${serviceName || serviceStorage}`)
      .on('value', snapshot => {
        let orderArr = [];
        snapshot.forEach(childSnapshot => {
          orderArr.push({
            snapshotKey: childSnapshot.key,
            username: childSnapshot.val().username,
          });
        });
        this.setState(
          prevState => ({
            orders: orderArr.filter(
              order =>
                !prevState.rejectedOrders.some(
                  key => order.snapshotKey === key,
                ),
            ),
            loading: false,
          }),
          () => console.log(this.state.orders), // I don't git anything if i add or delete rejected orders
        );
        console.log(orderArr); // I don't git anything if i add or delete rejected orders
      });
  };



 getRejectedOrders = async () => {
    let uid = auth().currentUser.uid;
    database()
      .ref(`Providers/users/${uid}`)
      .on('value', snapshot => {
        let rejectedOrders = snapshot.val().rejectedOrders;
        this.setState({rejectedOrders}, () =>
          console.log(this.state.rejectedOrders), // here's i got every single time i add or delete item i can see it in console log
        );
      });
  };




 <OrdersList
          data={this.state.orders}
          extraData={this.state.orders.length} // i add it but it's not effected 
          screenName="OrderHomeDetails"
        />

【问题讨论】:

  • 如何在 UI 上呈现订单?你能展示一下 JSX 吗?
  • 再次检查@AnandUndavia
  • 我认为keyExtractor={(item, index) =&gt; index.toString()} 是问题所在。尝试将其更改为keyExtractor={() =&gt; Math.random()}。如果可行,则意味着 key 每次都是相同的,这就是列表未更新的原因,您可能想提出一个适当的函数,从 item 中提取 key
  • 很遗憾我收到了这个错误Failed child context type: Invalid child context 'virtualizedCell.cellKey' of type 'number' supplied to 'CellRenderer', expected 'string'.
  • 试试:keyExtractor={() =&gt; Math.random().toString()}

标签: javascript reactjs react-native firebase-realtime-database


【解决方案1】:

您可以使用标志 isMounted 来检查何时使用 setState。关于状态不立即更新的问题,可以使用 ref.current 查看更改后立即更新。

【讨论】:

    【解决方案2】:

    每当rejectedOrders 更新时,您都应该更新orders。另外,记得unsubcribe listeners 避免内存泄漏

      constructor(props) {
        super(props);
        this.allOrders = [];
        this.rejectedOrders = [];
        this.state = {
          orders: [],
        }
      }
    
      componentWillUnmount() {
        database()
          .ref(`Providers/CategoriesOrders/${serviceName || serviceStorage}`)
          .off('value', this.ordersCallback);
        database()
          .ref(`Providers/users/${uid}`)
          .off('value', this.rejectedOrderCallback);
      }
    
      fetchOrders = async () => {
        ...
        database()
          .ref(`Providers/CategoriesOrders/${serviceName || serviceStorage}`)
          .on('value', this.ordersCallback);
      };
    
      getRejectedOrders = async () => {
        let uid = auth().currentUser.uid;
        database()
          .ref(`Providers/users/${uid}`)
          .on('value', this.rejectedOrderCallback);
      };
    
      ordersCallback = (snapshot) => {
        let orderArr = [];
        snapshot.forEach(childSnapshot => {
          orderArr.push({
            snapshotKey: childSnapshot.key,
            username: childSnapshot.val().username,
          });
        });
        this.allOrders = orderArr;
        this.updateData()
      }
    
      rejectedOrderCallback = (snapshot) => {
        this.rejectedOrders = snapshot.val().rejectedOrders;
        this.updateData();
      }
    
      updateData() {
        const orders = this.allOrders.filter(order => this.rejectedOrders.some(key => order.snapshotKey === key));
        this.setState({ orders });
      }
    

    【讨论】:

    • 感谢您的回复,但我收到了两个错误第一个 Cannot read property 'forEach' of undefined 2- Warning: Each child in a list should have a unique "key" prop.
    • 错误1,你需要更新自己,当你从数据库中获取数据时,轮到你准备数据了。错误 2,FlatList 需要每个项目都有一个唯一的 id,默认它会从每个项目中获取 id 字段。如果您的订单商品没有id,则需要在keyExtractor={order =&gt; order.&lt;uniqueId&gt;}中指定一个唯一值
    • 谢谢 1- 但是当我记录快照时,我可以在我的日志中看到所有订单!刷新应用两次或更多次后它运行良好,为什么!
    • 这是一个不错的方法,但是我有一些问题,在ordersCallBack() 你调用this.updateData(this.allOrders) "with parameter" 但是在rejectedOrdersCallback() 你没有将任何参数传递给this.updateData() 为什么?
    • 它不影响内存,updateData 只是从this.allOrdersthis.rejectedOrders 准备显示数据。
    猜你喜欢
    • 1970-01-01
    • 2021-11-07
    • 2018-08-05
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 2018-07-25
    相关资源
    最近更新 更多