【问题标题】:How to correctly large state updates in React Native?如何在 React Native 中正确地进行大型状态更新?
【发布时间】:2017-11-23 11:14:01
【问题描述】:

我正在编写一个小型 ReactNative 应用程序,它允许用户邀请人们参加活动。

该设计包括一个受邀者列表,每个受邀者都附有一个复选框,用于邀请/取消邀请所述受邀者。列表顶部的另一个复选框同时对所有被邀请者执行批量邀请/取消邀请。最后,最终将使用一个按钮来发送邀请。

因为每个元素的状态取决于另一个元素所做的更改,所以每当用户对其中一个元素执行操作时,我经常需要重新渲染整个 UI。但是,虽然这可以正常工作,但它给我带来了很多性能问题,as shown in this video

这是我正在使用的代码:

import React, { Component } from 'react';
import { Container, Header, Title, 
    Content, Footer, FooterTab, 
    Button, Left, Right, 
    Center, Body, Text, Spinner, Toast, Root , CheckBox, ListItem, Thumbnail} from 'native-base';

import { FlatList, View } from 'react-native';

export default class EventInviteComponent extends Component {


constructor(props) {
    super(props);
    console.disableYellowBox = true; 

    this.state = {
        eventName: "Cool Outing!",
        invitees:[]
    }

    for(i = 0; i < 50; i++){
        this.state.invitees[i] = { 
            name: "Peter the " + i + "th",
            isSelected: false,
            thumbnailUrl: 'https://is1-ssl.mzstatic.com/image/thumb/Purple111/v4/62/08/7e/62087ed8-5016-3ed0-ca33-50d33a5d8497/source/512x512bb.jpg'
        }
      }


    this.toggelSelectAll = this.toggelSelectAll.bind(this)
}

toggelSelectAll(){
    let invitees = [...this.state.invitees].slice();
    let shouldInviteAll = invitees.filter(invitee => !invitee.isSelected).length != 0

    let newState = this.state;
    newState = invitees.map(function(invitee){
        invitee.isSelected = shouldInviteAll;
        return invitee;
        });
    this.setState(newState);
}


render() {

    let invitees = [...this.state.invitees];

    return (
        <Root>
            <Container>

                <Content>
                    <Text>{this.state.eventName}</Text>

                    <View style={{flexDirection: 'row', height: 50, marginLeft:10, marginTop:20}}>
                        <CheckBox 
                    checked={this.state.invitees.filter(invitee => !invitee.isSelected).length == 0}
                    onPress={this.toggelSelectAll}/>
                        <Text style={{marginLeft:30 }}>Select/deselect all</Text>
                    </View>

                    <FlatList
                    keyExtractor={(invitee, index) => invitee.name}
                    data={invitees}
                    renderItem={(item)=> 
                        <ListItem avatar style={{paddingTop: 20}}>
                            <Left>
                              <Thumbnail source={{ uri: item.item.thumbnailUrl}} />
                            </Left>
                            <Body>
                                <Text>{item.item.name}</Text>
                                <Text note> </Text>
                            </Body>
                            <Right>
                                <CheckBox 
                                checked={item.item.isSelected}/>
                            </Right>
                        </ListItem>}/>

                </Content>

                <Footer>
                    <FooterTab>
                        <Button full
                         active={invitees.filter(invitee => invitee.isSelected).length > 0}>
                            <Text>Invite!</Text>
                        </Button>
                    </FooterTab>
                </Footer>

            </Container>
        </Root>);
    }
}

【问题讨论】:

  • 我在这里有一些建议:#1。您不需要在渲染函数中克隆数组。 #2。状态不应该像您那样包含所有内容。我认为这可能是受邀者的 ID 数组。 #3。奇怪的是,FlatList 在这里没有任何改进。您可能希望获取对复选框的引用并切换每个复选框,而不是重新渲染所有内容。希望对您有所帮助

标签: react-native react-native-android react-native-flatlist


【解决方案1】:

在您的代码中,在类方法toggelSelectAll() {...} 中,您可以使用this.state = ... 直接修改状态,这是要避免的。只在你的类中使用this.state = ... constructor() {...} 来初始化状态,你应该只使用this.setState({...}) 在其他地方更新状态。

不确定这是否有助于解决您的性能问题,但请尝试将 toggelSelectAll() 替换为以下内容:

toggelSelectAll() {
  const {invitees} = this.state;

  const areAllSelectedAlready = invitees.filter(({isSelected}) => !isSelected).length === 0;

  this.setState({
    invitees: invitees.map(invitee => ({
      ...invitee,
      isSelected: !areAllSelectedAlready
    }))
  });
}

祝你好运!并且,如果您希望我重构您的上述代码以删除构造函数中的第二个 this.state = ...,请告诉我(同样,在编写 React 时应该避免这样做)。

【讨论】:

  • 你是对的。有一个错字。我现在纠正了它,但没有,它无助于提高性能。
  • 啊!明白了。尽管如此,我不确定您为什么会遇到性能问题。这很奇怪,因为仅更新 50 条记录不会导致此问题。
  • 由于某种原因,复选框动画被 JS 线程阻塞。
  • &lt;CheckBox&gt; checked 属性可能有问题吗?也许使用invitees.filter() 的计算很慢?
  • 同样,尝试在某处添加一个 console.log() 语句 --> 可能会发生一个大且不必要的循环,并且 render() 方法在其中一个组件中被调用了 1000 多次?
【解决方案2】:

我建议:

  • 通过创建多个组件来划分代码,这样您就不会拥有大量的render()

  • 使用 Redux 存储受邀者/全局状态,因此您可以选择在修改时应该重新渲染哪些组件

这是学习 React Native 的好方法!

【讨论】:

    猜你喜欢
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    相关资源
    最近更新 更多