反应本机性能问题

iRo*_*tia 13 reactjs react-native

我正在使用congap api来首先获取大约1500+加密货币的数据,然后使用Web-socket来更新加密货币的更新值.

我在这里使用redux来管理我的状态

在我的内部componentDidMount(),我正在调用一个可以获取硬币价值的redux动作 fetchCoin

componentDidMount() {
    this.props.fetchCoin()
  }
Run Code Online (Sandbox Code Playgroud)

然后在return我做这样的事情

 <FlatList
           data={this.state.searchCoin ? displaySearchCrypto : this.props.cryptoLoaded}
           renderItem={({ item }) => (
           <CoinCard
              key={item["short"]}
              coinShortName = {item["short"]}
              coinName = {item["long"]}
              coinPrice = {item["price"].toFixed(2)}
              percentChange = {item["perc"].toFixed(2)}
              />
Run Code Online (Sandbox Code Playgroud)

然后我有一个web-socket来更新加密货币的价值

 componentDidUpdate() {
    if (this.state.updateCoinData || this.updateCoinData.length < 1 ) {
      this.updateCoinData = [...this.props.cryptoLoaded];
     this.setState({updateCoinData: true})
    }
      this.socket.on('trades', (tradeMsg) => {
      for (let i=0; i< this.updateCoinData.length; i++) {

        if (this.updateCoinData[i]["short"] == tradeMsg.coin ) {

        //Search for changed Crypto Value
       this.updateCoinData[i]["perc"] = tradeMsg["message"]["msg"]["perc"]
       this.updateCoinData[i]["price"] = tradeMsg['message']['msg']['price']

        //Update the crypto Value state in Redux
        this.props.updateCrypto(this.updateCoinData);

          }
        }
      })
  }
Run Code Online (Sandbox Code Playgroud)

现在,虽然这项工作,问题是这会让我的应用程序像地狱一样慢,因为每当套接字发送新数据时,它必须呈现每个组件,因此触摸和搜索等事件需要花费大量时间来执行.[更新]事实证明我的应用程序正在渲染一些东西如果我删除套接字连接,请查看更新2

[问题:]我应该怎样做才能提高App的性能?(不喜欢使用状态或使用DOM来更新我的应用程序等等).

[更新1:]我用的https://github.com/irohitb/Crypto而这两个是js文件,所有的逻辑正在发生 https://github.com/irohitb/Crypto/blob/master/src/container /cryptoContainer.js https://github.com/irohitb/Crypto/blob/master/src/components/CoinCard.js 我也从map转到Flatlist.

[更新:2]我发现在我的应用程序中发生了无休止的渲染,这可能让我的线程忙碌(我的意思是它是无穷无尽的,不必要地传递道具).我在单独的Stackoverflow线程上问了同样的问题,但没有得到正确的响应,因为它与性能有关,我想在这里给它一个赏金.

请检查此线程:无限渲染React

[答案更新:]虽然这里有很多很好的答案,但万一有人想了解它是如何工作的,你可以克隆我的存储库并提交之前返回.我已将提交链接到我的问题已解决的位置(因此您可能需要返回并查看我做错了什么).此外,所有答案都非常有用,不难理解,所以你一定要仔细阅读.

bas*_*ase 6

每次组件更新时,它都会启动一个新的套接字,导致内存泄漏,并导致this.props.updateCrypto(updateCoinData);对同一数据多次调用.这可以通过打开插座componentDidMount()并将其关闭来解决componentWillUnmount().

您还可以缓冲多个记录更新,并每隔几秒钟一次更改FlatList数据.

编辑,工作示例(App.js):

import React, { Component } from 'react';
import { Text, View, FlatList } from 'react-native';
import SocketIOClient from 'socket.io-client';

type Props = {};
export default class App extends Component<Props> {
    constructor(props) {
        super(props);

        this.currencies = {};
        this.state      = {
            currenciesList: [],
        }
    }

    componentDidMount() {
        this.socket = SocketIOClient('https://coincap.io');

        this.socket.on('trades', (tradeMsg) => {
            const time = new Date();

            // Store updates to currencies in an object
            this.currencies[tradeMsg.message.msg.short] = {
                ...tradeMsg.message.msg,
                time: time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds(),
            };

            // Create a new array from all currencies
            this.setState({currenciesList: Object.values(this.currencies)})
        });
    }

    componentWillUnmount() {
        this.socket.disconnect();
    }

    render() {
        return (
            <FlatList
                data={this.state.currenciesList}
                extraData={this.state.currenciesList}
                keyExtractor={(item) => item.short}
                renderItem={({item}) => <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
                    <Text style={{flex: 1}}>{item.time}</Text>
                    <Text style={{flex: 1}}>{item.short}</Text>
                    <Text style={{flex: 1}}>{item.perc}</Text>
                    <Text style={{flex: 1}}>{item.price}</Text>
                </View>}
            />
        );
    }
}
Run Code Online (Sandbox Code Playgroud)


xad*_*adm 5

有许多标准方法可以提高应用程序的性能,最常见的是:

  • 使用通常的反应优化(shouldComponentUpdate,PureComponent - 读取文档)
  • 使用虚拟列表(限制数据的可见部分)

在这种情况下,我会添加:

不要在优化之前处理数据 - 格式化未更改的数据至少是不必要的.您可以插入中间组件(优化层),该组件将<CoinCard />仅将格式化数据传递/更新为"原始数据"更改.

您可能不需要终极版在所有(在状态存储数据)当数据在同一个地方/结构简单,使用.当然,您可以将redux用于其他全局共享应用程序状态(fe过滤选项).

使用<FlatList />(react-native),搜索更合适?

UPDATE

有些代码在平均时间(repo)中发生了变化,此时(08.09)仍存在一个问题,可能导致内存泄漏.

您正在呼叫this.socket.on每个componentDidUpdate呼叫(错误编码的条件) - 不断添加新的处理程序!

componentDidUpdate() {
  // call all ONLY ONCE afer initial data loading
  if (!this.state.updateCoinData && !this.props.cryptoLoaded.length) {
    this.setState({updateCoinData: true}) // block condition
    this.socket.on('trades', (tradeMsg) => {

      // slice() is faster, new array instance
      // let updateCoinData = [...this.props.cryptoLoaded]; 
      let updateCoinData = this.props.cryptoLoaded.slice();

      for (let i=0; i<updateCoinData.length; i++) {
        //Search for changed Crypto Value
        if (updateCoinData[i]["short"] == tradeMsg.coin ) {

          // found, updating from message
          updateCoinData[i]["long"] = tradeMsg["message"]["msg"]["long"]
          updateCoinData[i]["short"] = tradeMsg["message"]["msg"]["short"]
          updateCoinData[i]["perc"] = tradeMsg["message"]["msg"]["perc"]
          updateCoinData[i]["mktcap"] = tradeMsg['message']['msg']["mktcap"]
          updateCoinData[i]["price"] = tradeMsg['message']['msg']['price']

          //Update the crypto Value state in Redux
          this.props.updateCrypto(updateCoinData);

          // record found and updated, no more looping needed
          break;
        }
      }
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

次要错误:初始提取状态在reducer中设置为true.

搜索性能问题我会看<CoinCard />:

  • 使它成为PureComponent;
  • increased并且decreased不需要在强制不必要的渲染调用的状态下保存;
  • 我会使用更新时间(不保存在状态,只是作为父项中的prop传递,仅用于更新的行,在updateCoinData上面的代码中)并且仅为可见项导出方向(仅检查0和符号)差异(已计算perc)(来自渲染)并且仅在时间限制期间(渲染时间和数据更新道具之间的差异).也可以用.setTimeout
  • 最后删除componentWillReceiveProps,componentDidUpdate并且shouldComponentUpdate(高度?)提高性能;


bas*_*ase 3

正如 Bhojendra Rauniyar 所说,您应该在 CoinCard 中使用 shouldComponentUpdate。您可能还想更改您的 FlatList,缩小的示例在 ScrollView 中具有 FlatList,这会导致 FlatList 完全展开,从而立即渲染其所有项目。

class cryptoTicker extends PureComponent {

      componentDidMount() {
        this.socket = openSocket('https://coincap.io');
        this.props.fetchCoin()
        this.props.CurrencyRate()

        this.socket.on('trades', (tradeMsg) => {

            for (let i=0; i< this.updateCoinData.length; i++) {

                if (this.updateCoinData[i]["short"] == tradeMsg.coin ) {

                    //Search for changed Crypto Value
                    this.updateCoinData["short"] = tradeMsg["message"]["msg"]["short"]
                    this.updateCoinData[i]["perc"] = tradeMsg["message"]["msg"]["perc"]
                    this.updateCoinData[i]["price"] = tradeMsg["message"]['msg']['price']

                    //Update the crypto Value state in Redux
                    this.props.updateCrypto(this.updateCoinData);

                }
            }
        })

      }

      componentWillReceiveProps(newProps){
        // Fill with redux data once
        if (this.updateCoinData.length < 1 && newProps.cryptoLoaded) {
            this.updateCoinData = [...newProps.cryptoLoaded];
        }
      }

    render() {

        return (
            <View style={{height: '100%'}}>
                <Header/>
                <FlatList
                    style={{flex:1}}
                    data={this.props.cryptoLoaded}
                    keyExtractor={item => item.short}
                    initialNumToRender={50}
                    windowSize={21}
                    removeClippedSubviews={true}
                    renderItem={({item, index}) => (
                        <CoinCard
                            index={index}
                            {...item}
                        />
                    )}
                />
            </View>
        )
    }
}

class CoinCard extends Component {

    shouldComponentUpdate(nextProps) {
        return this.props.price !== nextProps.price || this.props.perc !== nextProps.perc
    }

    render() {
        console.log("here: " + this.props.index);

        return (
            <View>
                <Text> {this.props.index} = {this.props.long} </Text>
            </View>
        )
    }
}
Run Code Online (Sandbox Code Playgroud)