What would be some general tips & tricks you personally know and tested that work for improving performance in a React.js component ?
Personally the best tip I could provide is to avoid writing logic that updates your component-state to frequently. You do not want your component to constantly be calling this.setState({}) because it creates a sort of distorted lag which may affect your application both visually and performantly.
Definitely avoid writing stuff like:
componentDidUpdate(){
this.setStatE({
field: this.props.newData
})
}
But while also on that topic, make use of your lifecycle methods, particularly componentDidMount() and componentDidUpdate() these are incredibly useful for controlling logic inside your component. In a way they can also enhance your component by giving it a sort of breathing mechanism for processing data.
Lastly, this is more-so a preference, but if you want to have good code-readability, I would suggest creating a function to generate your mark-up instead of writing it directly inside your render-method.
Considering the following code:
import React from "react"
class Example extends React.Component{
state = {
tests: [{id: 1, name: "test1"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}]
}
render(){
const tests = this.state.tests
return(
<div>
{ tests.length > 0 && tests.map((test) => {
return <div>{test.name}</div>
})}
</div>
)
}
}
This code is perfectly fine as is, but you can make it easier to read for someone else just by making another function for your mark-up.
Revised:
import React from "react"
class Example extends React.Component{
state = {
tests: [{id: 1, name: "test1"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}]
}
createTests = () => {
const tests = this.state.tests
if(tests.length > 0){
return tests.map((test) => {
return <div>{test.name}</div>
})
}
}
render(){
const tests = this.state.tests
return(
<div>
{this.createTests()}
</div>
)
}
}
Does the same thing, but now it's very clear what we're trying to accomplish inside our render method.
There are couple of things we have implemented.
We used one plugin to figure out how many wasted render we have and this was 60 %.
To address this there are couple of things we have done.
1.We can use life cycle hook up to figure out is there any change in property.
2.Minimize the parent child relation ship between component.
3.If we are using any kind of redux to manage the state then we should be having top level component connected to store and pass the data as props to child component.
4.for Asyc call care should be taken to place if we want it in compoentDidMount or ComponentWillmount as if the data of asyc call is required in child component or not.
There are many options to optimize your React Application, too much to cover on one answer. My advice here is, start you App, open DevTools and go to Audit, start the Lighthouse test. The Test will show certain actions which can be done to optimize your code and also ressources to read about.
If you have more concrete questions ask then. Your current question is kinda too much to cover in one answer. Or post code, which you want optimized.
Related
I am trying to construct 1-minute candlestick.
I have a component that will continuously passing a number (the trade price) to his child component.
This child component will keep update its state: (High, Low, Open, Close) base on the new number he gets from the parent. (e.g. if the number coming in, is higher than the current this.state.high, it will update this.state.high to the new number) After every minute a setInterval function it will take the states and construct a candle and pass it down to its own children.
the state are:
high, low, open, close, newCandle
I got it working by using
shouldComponentUpdate(nextProps:props, nextState:state){
if(this.props !== nextProps)
this.updateStates(nextProps.newTradePrice); //will update the high, low, open, close state
if(JSON.stringify(nextState.nextMinuteCandle) !== JSON.stringify(this.state.nextMinuteCandle) ) //once the one minute interval is up, there will be a function that will auto set the newCandle state to a new Candle base on the current high, low, open, close state
return true;
return false;
}
I read in the document that shouldComponentUpdate should only be used for optimization not to prevent something to reRender. I am using this to prevent reRender and infinite loop.
I've been stuck on this for days, I cant figure out a way to design this better. Any advice on how to design this better?
2nd related question:
In fact I am relying on shouldComponentUpdate for almost ALL my component too. This can't be right. e.g.
I have a CalculateAverageVolume child component, that takes in the this.state.newCandle. And update the volume every time the newCandle changes (i.e. every minute)
constructor(props: props) {
super(props);
this.state = {
[...],
currentAverage: 0,
showVolume: true
};
}
onCloseHandler()
{
this.setState({showVolume: false});
}
updateAvg(newCandleStick: CandleStick){
//do caluation and use this.setState to update the this.state.currentAverage
}
shouldComponentUpdate(nextProps:props, nextState:state)
{
if(JSON.stringify(this.props.candleStick) !== JSON.stringify(nextProps.candleStick) || this.state.showVolume !== nextState.showVolume){
this.updateAvg(nextProps.candleStick);
return true;
}
return false;
}
render() {
return (
<>
{(this.state.showVolume &&
<IndicatorCard
cardHeader="Volume"
currentInfo={this.state.currentAverage.toString()}
onCloseHandler={()=>this.onCloseHandler()}>
</IndicatorCard>
)}
</>
);
}
}
Can someone please teach me how to design this or restructure this? This works perfectly, but doesn't seem like the right way to do it
I would simplify the component like below.
import { useMemo, useState, memo, useCallback } from "react";
function Component({ candleStick }) {
// use props here to calculate average
const updateAverage = () => 0; // use candleStick props to calculate avg here
const [showVolume, setShowVolume] = useState();
// Compute the average from prop when component re-renders
// I would also add useMemo if `updateAverage` is an expensive function
// so that when prop remains same and `showVolume` changes we don't need to calculate it again
const currentAverage = useMemo(updateAverage, [candleStick]);
const onCloseHandler = useCallback(() => setShowVolume(val => !val), []);
return showVolume ? (
<IndicatorCard
cardHeader="Volume"
currentInfo={currentAverage}
onCloseHandler={onCloseHandler}
/>
) : null;
}
// If true is returned, component won't re-render.
// Btw React.memo by default would do shallow comparison
// But if deep comparison function is required, I would use lodash or other utility to do the check instead of JSON.stringify.
const arePropsEqual = (prev, next) =>
isEqual(prev.candleStick, next.candleStick);
export default memo(Component, arePropsEqual);
shouldComponentUpdate is usually reserved for discrete events that you can control. Howevr, it seems like you are dealing with a continuous stream of data.
Two ways to handle it:
Pass down a function reference that handles a stream to the child component and let that handle you state updates in your child component.
Use the context API to inform child component about the changes
Reference implementation :
Upadting State with Context API : https://javascript.plainenglish.io/react-context-api-part-2-updating-state-through-a-consumer-7be723b54d7b
Streams : https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams
React with Streams : https://blog.bitsrc.io/how-to-render-streams-with-react-8986ad32fffa
I hit the same spot you're in when starting React. The problem here is that React, at least the basic aspects of it, isn't enough when you're talking about data flow. What you need to look into is a React data management framework, of which Redux is probably the most popular. Go look at Redux and make sure you're looking at the latest documentation based around hooks.
You'll say to yourself "Oh! That makes perfect sense" - I know I did.
Other, similar frameworks are React Query and React's own Context API. The main point I'm trying to make is that you really need data management to do the thing you're looking for.
It is a common practice to pass in the form of a prop, from a root component A, to a subcomponent B, a function that will change the state of A. Like so:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'foo'
};
this.handleNameChange = this.handleNameChange.bind(this);
}
render() {
return (<NameChanger name={this.state.name} onNameChange={this.handleNameChange} />)
}
handleNameChange: function(newName) {
this.setState({
name: newName
});
}
}
Now as you can see NameChanger is one level down only so not a big issue there. But what if it had been down 3 or even 4 levels? We would have had to pass it down the chain of components and that bothers me big time. Is there a way to make a function globally available within the app?
I looked at Context (https://reactjs.org/docs/context.html) but I am not sure it is the right design choice for globally available functions. Or is it?
Thanks
In a typical React application, data is passed top-down (parent to
child) via props, but this can be cumbersome for certain types of
props (e.g. locale preference, UI theme) that are required by many
components within an application. Context provides a way to share
values like these between components without having to explicitly pass
a prop through every level of the tree.
https://reactjs.org/docs/context.html
Try using Redux or Mobx(very easy to start with) as state management library to solve this problem.
I have a legacy Backbone app which I have begun to rewrite in React. The app has a main view containing two subviews, arranged vetically. The top panel displays some data, and the bottom one displays the result of some algorithm taking this data as input. Since I have many different data sources, each with a different algorithm applied to it, I have an abstract base View class, which I then subclass for each data source, adding, decorating and overriding methods as necessary. Somewhat like this:
// Base View.
const BaseView = Backbone.View.extend({
events: {},
initialize() {
this.subViewA = // instantiate subview...
this.subViewB = // instantiate subview...
},
generateResultData() {
// 'Abstract' method which should be specialised to generate data rendered by subViewB...
},
render() {
// render subviews...
},
});
// Derived View.
const Derived = BaseView.extend({
events: {
// event handlers...
},
add(a, b) {
return a+b;
},
// additional methods...
generateResultData() {
return {
result: this.add(2,2);
}
},
})
This results in a shallow hierarchy of many similar View classes. It's all terribly imperative, but it's a simple, intuitive and easy-to-reason-about pattern, and just works. I'm struggling to see how to achieve the same thing in React, however. Given that subclassing of subclasses of React.Component is considered an anti-pattern, my focus has naturally been on composition, and in particular Higher Order Components. HOCs (which I find beautiful, but unintuitive and often just downright confusing) seem to involve adding general features, rather than specialising/refining something more general. I have also considered passing in more specialised versions of Componenet methods through props. but that just means I have to use the same boilerplate Component definition over and over again:
// General functional component, renders the result of prop function 'foo'.
function GeneralComponent(props) {
const foo = this.props.foo || ()=>"foo";
return (
<div>
<span> { this.props.foo() } </span>
</div>
)
}
// Specialised component 1, overrides 'foo'.
class MySpecialisedComponent extends React.Component {
foo() {
return this.bar()
}
bar() {
return "bar"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
// Specialised component 2, overrides 'foo' and adds another method.
class MyOtherSpecialisedComponent extends React.Component {
foo() {
return this.bar() + this.bar()
}
bar() {
return "bar"
}
baz() {
return "baz"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
The above is a very simplistic case, obviously, but essentially captures what I need to do (though I would of course be manipulating state, which the example does not do, for simplicity). I mean, I could just do things like that. But I want to avoid having to repeat that boilerplate all over the place. So is there a simpler and more elegant way of doing this?
Generally, if a component is stateless and doesn't use lifecycle hooks, there are no reasons for it to be Component class. A class that acts as a namespace and doesn't hold state can be considered an antipattern in JavaScript.
In constrast to some other frameworks, React doesn't have templates that would need to map variables in order for them to be available in view, so the only place where bar function needs to be mentioned is the place where it's called. JSX is an extension over JavaScript, JSX expressions can use any names that are available in current scope. This allows to compose functions without any classes:
const getBar => "bar";
const getBaz => "baz";
const getBarBaz => getBar() + getBaz();
const MySpecialisedComponent = props => <GeneralComponent foo={getBar} />;
const MyOtherSpecialisedComponent = props => <GeneralComponent foo={getBarBaz} />;
An anonymous function could be passed as foo prop instead of creating getBarBaz but this is generally discouraged because of unnecessary overhead.
Also, default prop values could be assigned with defaultProps without creating new ()=>"foo" function on each component call:
function GeneralComponent({ foo }) {
return (
<div>
<span> {foo()} </span>
</div>
)
}
GeneralComponent.defaultProps = { foo: () => 'foo' };
IMO what is throwing you off isn't inheritance vs composition, it's your data flow:
For example, many of my derived views need to do custom rendering after the main render. I'm using a third-party SVG library, and the data rendered into the 'result' subview is derived from analysis of rendered SVG elements in the main data view above it
So what you're trying to do here is have a child update props of a distantly related component after render, correct? Like this?
// after the svg renders, parse it to get data
<div id="svg-container">
<svg data="foo" />
<svg data="bar />
</div>
// show parsed data from svg after you put it through your algos
<div id="result-container">
// data...
</div>
There's a lot of state management libraries out there that will help you with this problem, that is, generating data in one component and broadcasting it to a distantly related component. If you want to use a tool built-in to react to address this you may want to use context, which gives you a global store that you can provide to any component that wants to consume it.
In your example your child classes have data-specific methods (add, etc.). IMO it's more typical in react to have a generic class for displaying data and simply passing it down map functions as props in order to rearrange/transform the rendered data.
class AbstractDataMap extends PureComponent {
static defaultProps = {
data: [],
map: (obj, i) => (<div key={i}>{obj}</div>)
};
render() {
const { data, map, children } = this.props;
const mapped = data.map(map);
return (
<Fragment>
{mapped.map((obj, i) => (
children(obj, i)
))}
</Fragment>
);
}
}
// in some other container
class View extends Component {
render() {
return (
<div>
<AbstractDataMap data={[1, 2, 3]} map={(n) => ({ a: n, b: n + 1 })}>
{({ a, b }, i) => (<div key={i}>a: {a}, b: {b}</div>)}
</AbstractDataMap>
<AbstractDataMap data={[2, 4, 6]} map={(n) => (Math.pow(n, 2))}>
{(squared, i) => (<div key={i}>squared: {squared}</div>)}
</AbstractDataMap>
</div>
);
}
}
IMO this pattern of using an HOC to abstract away the labor of explicitly using .map in your render calls (among other uses) is the pattern you are looking for. However, as I stated above, the HOC pattern has nothing to do your main issue of shared data store across sibling components.
Answering my own question, which I've never donw before...
So my question really arose from a concern that I would need to refactor a large, imperative and stateful codebase so as to integrate with React’s composition-based model (also with Redux). But it occurred to me after reading the (very insightful and helpful) responses to my question that my app has two parallel parts: the UI, and an engine which runs the algorithms (actually it's a music analysis engine). And I can strip out the Backbone View layer to which the engine is connected quite easily. So, using React’s context API I've built an ‘AnalysisEngineProvider', which makes the engine available to subcomponents. The engine is all very imperative and classically object-oriented, and still uses Backbone models, but that makes no difference to the UI as the latter has no knowledge of its internals - which is how it should be (the models will likely be refactored out at some point too)...
The engine also has responsibility for rendering the SVG (not with BB views). But React doesn’t know anything about that. It just sees an empty div. I take a ref from the div and pass it to the engine so the latter knows where to render. Beyond that the engine and the UI have little contact - the divs are never updated from React state changes at all (other components of the UI are though, obviously). The models in the engine only ever trigger updates to the SVG, which React knows nothing about.
I am satisfied with this approach, at least for now - even if it's only part of an incremental refactor towards a fully React solution. It feels like the right design for the app whatever framework I happened to be using.
let's imagine data that would look like that :
{
{
title: "great track",
tags: ["techno"]
},
{
title: "superb track",
tags: ["house", "90s"]
},
...
}
I render that in an html table, I have a component for the whole table, and a sub component for the tr (aka song title and tracks). so on each line I want to allow the users to be able to access a popup in which they can choose one or more tags for a song. I did it using reactstrap, it works ok.
I'm just a little disappointed by performance, it's quite ok, once it's built, but I saw how much longer it was to load when I added my modal on each line. So my first reflex, was to built only one modal in the parent component, and then use it from the sub component, and then I read articles on how, "one should not use the parent instance because it's bad"(tm).
I understand the point about dataflow, but in my example, having a modal waiting on each line while I'm sure I will never have two at the same time on screen feels like a waste of ressources.
Can anyone point me to an elegant way of building that kind of feature, in this particular context ?
Lifting state up to the parent component is a common practice in react, you can read articles in official documentation https://reactjs.org/docs/lifting-state-up.html
But there is one problem, when you use setState in your parent component, your songs table will render again and again, so you should care about it. One of the way is creating PureComponent for Songs table(if there is no changing in props, this component will not rerender)
I think, the code below is one of the way;
class Parent extends React.Component{
state={
tags: [],
songs: {
title: "great track",
tags: ["techno"]
},
{
title: "superb track",
tags: ["house", "90s"]
}
}
handlePopup(data){
this.setState({tags: data});
}
render(){
const {tags, songs} = this.state;
cons isShowModal = tags && tags.length
return (
<div>
{isShowModal && <Modal data={tags} />}
<SongsList data={songs} />
</div>
)
}
}
class Parent extends React.PureComponent{
render(){
const {data} = this.props;
return (
<table><tbody>...render songs data</tbody></table>
)
}
}
Of course using modal in child rows is a waste of resources. you need to add a modal to parent and use props to show/hide it. also, you should use the key prop for your list items.
By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
but when children have keys, React uses the key to match children in the original tree with children in the subsequent tree.
it's good for performance.
I"m new to firebase, just wrote a little simple test react component before putting all of data on to firebase, but unfortunately I couldn't make it work with Server Side Pre-Rendering. It's very important to make it SEO friendly for me, and I've searching around on the internet for the solution, but still couldn't really figure it out. please help me out with this. thanks very much in advance.
The simple code below will only generate the initial state with React-Snapshot, when I open the the page it will show initial state and then update to newer state. But I need to make the initial state object fetching data directly from Firebase and generate static html with React-Snapshot.
class FirebaseTestingComponent extends Component {
constructor(){
super();
this.state = {
speed: 10
};
}
componentWillMount(){
const rootRef = firebase.database().ref().child('react');
const speedRef = rootRef.child('speed');
speedRef.on('value', snap => {
this.setState({
speed: snap.val()
});
});
}
render(){
return (
<div>
<h1>{this.state.speed}</h1>
</div>
);
}
}
By SEO friendly I assume you want static content instead of dynamic (not an expert on SEO) but firebase runs asynchronously especially when you use .on() that's like websocket, doesn't matter if you do willmount or didmount this case.
My humble suggestion for the design is to fetch from firebase in your server before render the page (firebase support java and node for sure, not sure about the rest), and set initial state with that value you fetched, that will guarantee your initial state is from firebase. From that you can still use that .on() for later value coming in.