Tuesday, September 4, 2018

React native performance issue

Leave a Comment

I am using coincap api's to first fetch Data of about 1500+ crypto currency and then Web-socket to update the updated value of crypto Currency.

I a using redux to manage my state here

Inside My componentWillMount(), I am calling a redux action fetchCoin which fetches the value of the coin

componentWillMount() {     this.props.fetchCoin()   } 

And then In return I am doing something like this

 <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)}               marketCap = {(item["mktcap"]/1000000000).toFixed(4)}               percentChange = {item["perc"].toFixed(2)}               vwapData={item["vwapData"].toFixed(2)}               coinImage={"https://coincap.io/images/coins/" + item["long"] + ".png"}               /> 

Then I have a web-socket which updates the value of cryptocurrency like this

componentDidUpdate() {     var socket = openSocket('https://coincap.io');     var updateCoinData = [...this.props.cryptoLoaded];      socket.on('trades', (tradeMsg) => {       for (let i=0; i<updateCoinData.length; i++) {          if (updateCoinData[i]["short"] == tradeMsg.coin ) {          //Search for changed Crypto Value         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);            }         }      })   } 

Now, While this work, the problem is that this is slowing my app like hell since whenever the socket sends new data, it has to render every component and hence events like touch and search takes lot of time to execute.

[Question:] What should I do so that I can improve the performance of App? (Something like not using state or using DOM to update my app and so on).

[Update:] I am using https://github.com/irohitb/Crypto And these two are js files where all the logic is happening https://github.com/irohitb/Crypto/blob/master/src/container/cryptoContainer.js https://github.com/irohitb/Crypto/blob/master/src/components/CoinCard.js I have also move from map to Flatlist

2 Answers

Answers 1

Each time your component updates it starts a new socket which results in a memory leak and will cause this.props.updateCrypto(updateCoinData); to be called multiple times for the same data. This can be fixed by opening the socket in componentDidMount() and closing it in componentWillUnmount().

You can also buffer multiple record updates and change the FlatList data in one go every couple of seconds.

Edit, working example (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>}             />         );     } } 

Answers 2

The most obvious error is calling updateCrypto inside loop.

There're many standard ways to improve react app performance, the most common:

  • use usual react optimizations (shouldComponentUpdate, PureComponent - read docs)
  • use virtual lists (limit visible parts of data)

In this case I would add:

Don't process data before optimizations - f.e. formatting data that didn't changed is at least unnecessary. You can insert intermediate component (optimization layer) that will pass/update formatted data into <CoinCard /> only on 'raw data' change.

You might not need Redux at all (store data in state) when data is used in one place/simple structure. Of course you can use redux for other globally shared app state (f.e. filtering options).

Use <FlatList /> (react-native), search for sth more suitable?

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment