My top-level React component provides a context to all its children which is used to render UI. The context is an array, and a UI element is generated for each element in the array. Users can delete items from this array using buttons placed around the app and throughout the component tree.
The problem is when an element is deleted, the context takes a really long time to update and the app feels unresponsive. I know it's because it's async, but it's causing UX issues.
How can I make my app more responsive? Is there a way to force a state update?
I'm not sure how to approach fixing this. Would a state management lib work?
Turns out this is an issue with Chrome being a memory hog. I cleared caches and cookies, restarted chrome + server, and everything started working. What a silly thing to spend hours profiling your react app for! Hopefully this can help someone else.
Related
I'm working on an editor where a user adds, updates, and removes elements from a Canvas. I'm using FabricJS to actually do the drawing, but I don't think this matters.
Configuration is stored in POJOs in a redux store, and this is loaded into the canvas. As the user updates the canvas, either through the Fabric controls or through custom controls in React, these updates are emitted as events from Fabric and are propagated into my redux store.
The issue I'm having is finding a good way to handle state. The single biggest issue I'm dealing with is that each state update triggers a re-render which causes my entire editor canvas to flash as the canvas is torn down and re-rendered.
I have already implemented Adam's fantastic post on "persistent layouts" in NextJS. This actually solved another issue I had with flashes caused by page routing. However, I don't think I'm able to apply the same pattern to this.
I have tried the following:
memo - This doesn't work well for canvas as it still shows the flash, even if props don't change
useRef - Remove any reactive state that could cause a re-render from my component (and parents). However, I'm not sure how to then propagate state changes to and from the canvas.
In addition to the above, try using a global event bus for communication. This seems very annoying to work with and debug, so I want to ask before I implement this.
Has anybody solved a problem like this before? Specifically, how to get around re-rendering a Canvas while still enabling it to have some access to Redux state.
I'd be happy to provide a sample repo of the issue if this is unclear.
The performance of my React app is very poor and if you select "Highlight updates" in Chrome you'll find basically every single component re-renders with every move you make.
Open a simple modal? Everything in the app re-render, right down to the FontAwesome icons.
Click anywhere on the screen? Everything re-renders.
I've added really aggressive shouldComponentUpdates to basically every component.
I've used DeepDiff to check what's causing the updates (nothing is. The props/state are basically always the same).
What else can I check to try and solve this? There's nothing fancy at all going on, and most of the time it doesn't even involve Redux or anything like that.
I've just implemented React Router 4 in my React/Redux app which was using multiple entry points up to this point.
I changed my code to have a single entry point and set up a catch-all route on the server side so that react router would handle requests on the client side.
Initially, everything seems to work OK but it takes a long long time before the right component is displayed. As soon as I click the link, I see the URL in the browser address bar change immediately but I have to wait sometimes more than 10-15 seconds before the right component is loaded.
I've also noticed that after a click or two, it stops working all together.
I don't get any errors and I put a break point on the server to see if I'm somehow hitting the backend when I click a link but looks like I'm not even going to the backend.
How can I debug/troubleshoot this? React Router is just a bunch of components and there's not much code to speak of that I can debug.
Has anyone experienced this issue? I'd appreciate any ideas you may have. Thanks.
The answer was in this post: React Router v4 not rendering components
Because I'm using Redux, I needed to use withRouter.
Is there any way to get logs of which all React components get rendered or rerendered when any event/action is performed. I just want to check whether any unwanted React component is getting rerendered. I know we could achieve this by adding consoles in render function, componentWillReceiveProps or componentWillUpdate. But I have number of components in my webapp. Adding console statements in each component would be a mess. Is there a better way?
A nice option is to visualise React components in the chrome timeline. This lets you see which components exactly get mounted, updated, and unmounted and how much time they take relative to each other. That feature was added as part of the release of React 15.4.0. You can take a look at the official blogpost to get a better insight, but summing up, those are the steps to get it up and running:
Load your app with ?react_perf in the query string (for example, http://localhost:3000/?react_perf).
Open the Chrome DevTools Timeline tab and press Record.
Perform the actions you want to profile. Don't record more than 20 seconds or Chrome might hang.
Stop recording.
React events will be grouped under the User Timing label.
After that, you will get a cool visual representation of mounting, updating and unmounting of your different components over time
In addition to rauliyohmc answer. Profiling tool he described is really helpful and powerful, but if your task is just checking if there are unnecessary re-renders (i.e. ones which did not lead to DOM changes) you can use nice and simple react-addons-perf tool. It has printWasted method which will provide you info about wasted re-renders.
I was experimenting with React and rerendering iframes and I was not sure how React correctly rerenders iframes, especially ones which point to a text editor. Here is a jsFiddle showing this:
https://jsfiddle.net/augburto/fkqnm329/2/
The text editor I point to is not important but what I am doing is when you click Trigger Update, it will call a setInterval which will constantly set a new state and thus trigger a rerender.
What I thought might happen is that when I'm typing in the iframe which has a textarea, it will inevitably rerender and thus make me lose my text editor position but somehow I am able to type seamlessly without any issues despite seeing the rerenders come through in the console.log. Note I'm not suggesting it should do this -- I'm just wondering why it doesn't do that. I know React internals do some smart things like transactions but I wouldn't expect it to maintain my cursor position or what I have selected.
So how does React handle rerendering iframes more specifically? I have read articles (i.e. this and this but they don't shed a lot of light on it I feel). Is it any different from regular DOM elements?
Okay so after some time, I think I believe I discovered the answer. In general, because React just creates a virtual DOM and does a diff behind the scenes, it really is only looking at the iframe element and not what is generated. That is a completely separate thing where the iframe creates its own browsing context. Reading the MDN documentation on iframe was really informative:
The HTML element represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window.
I think React does do some special things when it comes to parsing an iframe but overall it doesn't deviate too much in general.
Also something that I think might be informative is how React handles input elements in general -- take a look at Controlled Components in general for Forms as React has a completely separate and special way of handling those cases.