React toolbox - Circular ProgressBar only animating rotation while loading JSON - reactjs

Edit: It seems that the problem was not with the loading part, but it was actually react that didn't like handling so much elements. I will update this post with details as soon as I have a chance to confirm what was happening. My first test JSON was a bunch of duplicated entries (so my file would take some time to load) that triggered some component rendering, I had something like ~40000 entries in my Json. Testing with a new json containing only 3 entries, each with a lot of nested data, so my file is still heavy and takes some time to load, did fix the issue.
I absolutely fail to understand how this is even possible:
I have a json that I'm loading on http://code.pensionsmilitaires.com/codes
During load time, the circle path element is not animated. Just wait for the json to finish loading to see the same ProgressBar animated correctly...
Here is my render function
render() {
console.log("Rendering");
if (this.state.codes.length < 1) {
return (
<ProgressBar type="circular" mode="indeterminate" multicolor/>
);
}
return (
<div>
<ProgressBar type="circular" mode="indeterminate" multicolor/>
<h2>Liste des codes disponibles</h2>
<div>
{this.state.codes.map((code, i) => (
<CodeSummary key={i} code={code}/>
))}
</div>
</div>
);
}
If anyone has an idea on how I can fix this, that would be awesome!
Thanks for reading my question anyway ^^

So a few years later, just for the sake of making sure anyone having the same kind of issue gets an answer.
React was actually being busy rendering thousands of elements, which froze the JavaScript based animation of the svg path-offset until React freed the thread.
As a result, the circular progress bar was not animating until React was done rendering.
In such cases where you have to render tons of things, windowing, or virtualizing a long list and React concurrent mode can be helpful

Related

How to debug #use-gesture bumping into something?

I'm using #use-gesture/react to drag a div around. The dragging is working just fine, but it keeps "bumping into" something. It appears that the motion is constrained by some containing div, but I can't for the life of me figure out why.
There are a few things I can imagine would be useful in diagnosing this, and I don't know how to do any of them :)
is there some event that fires when the component "runs into"
something, such that I can log to console what it's hitting?
is there any way to sort of visually inspect the DOM along the
z-index? (I have tried manually scouring the DOM, and can't see
anything that would cause a problem)
is there some way to watch local variables in the
react-developer-tools chrome extension?
I'm in no way constrained to the above — I'll take any and all advice on how to figure this out. More details, below.
Details
At a high level, I'm trying to add a moderately complicated component that has some draggable sub-components to part of a larger app. So, something like
const App = () => {
...
return (
<BrowserRouter >
... lots of code
<SomeComplicatedThing /> // with some sub-component that uses #use-gesture
...
Everything is very close to working, except for this annoying problem of the drag action appearing to run into some boundary.
After going over both the code and the DOM seemingly countless times and not being able to spot any reason for the problem, I decided to manually reconstruct one page to try and reproduce the problem and narrow it down to some specific component.
You can see that I'm using useDrag with the hook bound to a div. When the event fires, I put a copy of the div in a portal tied to the body, and then update the top and left style attributes inside of a useLayoutEffect block:
function App() {
function useColumnDragState() {
const [dragState, setDragState] = useState(null);
const bindDrag = useDrag(({ first, last, event, xy }) => {
if (first && event) {
event.preventDefault();
setDragState({
... // do state stuff
});
} else if (last) {
setDragState(null);
}
...
}, {});
return {
dragState,
dragEventBinder: bindDrag
};
}
const {
dragState,
dragEventBinder
} = useColumnDragState();
const eventHandlers = useMemo(() => dragEventBinder(), [dragEventBinder]);
const ColumnDragObject = ({ dragState }) => {
const referenceBoxRef = useRef(null);
const dragBoxRef = useRef(null);
const dragObjectPortal = dragState ? createPortal(
<div> // wrapper
<div ref={dragBoxRef}> // object positioner
<div> // object holder
<MyComponent /> //clone
</div>
</div>
</div>,
document.body
)
: null;
// set up initial position
...
// subscribe to live position updates without state changes
useLayoutEffect(() => {
if (dragState) {
dragState.updateListeners['dragObj'] = (xy: number[]) => {
if (!dragBoxRef.current) {
return;
}
dragBoxRef.current.style.left = `${xy[0]}px`;
dragBoxRef.current.style.top = `${xy[1]}px`;
};
}
}, [dragState]);
return <div ref={referenceBoxRef}>{dragObjectPortal}</div>
}
return (
<>
...
... // many layers of nested stuff
...
<div {...eventHandlers}> // draggable
<MyComponent /> // original
...
<ColumnDragObject dragState={dragState}/>
...
</>
);
}
export default App;
As I said, that's a much simplified version of both the component and the app, extracted out into one file. Much to my annoyance, it works just fine (i.e., it doesn't demonstrate the problem).
Next I did what maybe should have been my first step, and pulled <SomeComplicatedThing /> out into a stand-alone app with it at the top level:
import React, { Fragment } from 'react';
import { CssBaseline } from '#mui/material';
import SomeComplicatedThing from './components/SomeComplicatedThing';
function App() {
return (
<>
<CssBaseline enableColorScheme />
<div className="App">
<SomeComplicatedThing />
</div>
</>
);
}
export default App;
As I said, I probably should have done that first, because it does exhibit the problem. So, I opened the two up side-by-side, and stepped through the DOM. As far as I can see in the DOM between the working one (where I can drag stuff all over the page), and the not working one (where the drag appears to be constrained to some enclosing element) there is no difference in the hierarchy, and no difference in display, position, overflow, or z-index for any of the elements in the hierarchy.
So, how do I debug this from here? As I said in the beginning, my initial thoughts were
is there some event that fires when the component "runs into"
something, such that I can log to console what it's hitting?
I realise there's no actual running into things. The actual behaviour is that the pointer can move anywhere on the screen, but the <div> whose top and left attributes are being updated in the above code stops moving beyond a certain point (updates are still happening — if you move the pointer back from the "out of bounds" portion of the screen, the <div> moves again). One thought I have is that maybe some containing element has some attribute set, such that it precludes the xy coordinates from being updated, and there may be some event that fires when that "fail to update" occurs that can tell me which element is doing the blocking.
is there any way to sort of visually inspect the DOM along the
z-index? (I have tried manually scouring the DOM, and can't see
anything that would cause a problem)
I keep reading sort of parenthetically in digging around about this that there can sometimes be z-index issues with react-use-gesture. I had thought going the createPortal route would avoid any of those; nevertheless, it would be good to get some visual 3-D representation of the DOM and make sure I'm not missing something "obvious"
is there some way to watch local variables in the
react-developer-tools chrome extension?
As a last resort, I tried looking at what xy coordinates were being set, thinking that I might see something to make me go "aha!" when it runs into whatever is containing it. However, if I try and set a watch on xy naively in react-developer-tools, it doesn't work. In order to set a watch on it, I need to set a breakpoint in the enclosing function, and then set the watch. The problem is, since we're updating mouse position, every time you move at all, it triggers the break point, but if I remove the break point, it stops watching the variable. So ... how can I get it to dynamically watch a variable local to a function without setting a breakpoint?
And, of course, as I said at the beginning, any other debugging ideas are most definitely welcome!
Background
Given that I have the "simpler" version working, and that the normal course of development is to build-test-build-test-build-test ... until one gets to a finished product, it's natural to wonder how I got to the "complicated and broken" state in the first place. The answer is, my starting point is react-csv-importer. However, there are two aspects of that package which are rather explicitly the opposite of what I want: it's written in TypeScript and the UI theme is standalone. I'm removing the TypeScript parts to make it pure JavaScript, and making the UI be MUI.

I am trying to understand why componentDidUpdate is not firing for specific component

I am having some issues with a particular component not properly updating. This component is effectively modeled after each of the other components, the only difference that I can determine is that it receives props that are array elements; although I have switched the variable being passed so that it renders store elements that are working elsewhere, though I am still getting the same update issue.
The weird thing about this is that the component update does fire, but only when one of the other elements that is properly updating is triggered, so it logs the console object on this instance for two different checks within the componentDidUpdate function.
The overall design is a basic React/Redux app, with a component that is designed to hold/render the audio events. I have a MainLayout component that renders the AudioEngine component, followed by multiple "Panel" components that are only specified for the UI. It is this component that is passed the redux store. It appears that the redusx store is handling state properly, and is passing the data back as expected; however, it is only this element of the UI that is failing to properly trigger an update.
Within the AudioEngine component:
if(this.props.lfoRate != prevProps.lfoRate){
console.log(this.state.lfoRate)
this.setState({
lfoRate: this.props.lfoRate
}, () => {
this.lfo['osc'].frequency.value = this.state.lfoRate
});
}
Here is the return from the MainLayout component, which receives the stor/props (sorry this is still a bit of a work in progress):
return(
<div >
<Header />
<div style={mainLayoutStyle} className={"main-layout"}>
{
this.props.keyOn ? (<AudioEngine lfoRate={this.props.LFObj[2]} gain={this.props.masterGain} freq={this.props.masterFreq} oscArray={this.props.oscArray}
lfoType={this.props.LFObj[1]} lfoFreq={this.props.LFObj[3]} count={count}/>) : (count % 2 == 0 ? (<AudioEngine count={0} gain={0} freq={this.props.masterFreq} oscArray={this.props.oscArray}
lfoType={this.props.LFObj[1]} lfoRate={this.props.LFObj[2]} lfoFreq={this.props.LFObj[3]}/>) : (''))
}
<MainPanel keyToggle={this.props.keyToggle} changeMasterGain={this.props.changeMasterGain}
masterGain={this.props.masterGain} keyOn={this.props.keyOn} baseFrequency={this.props.masterFreq}
changeBaseFrequency={this.props.changeBaseFrequency} />
<div style={{display: 'flex', flexFlow:'column'}} >
<Oscillator addOsc={this.props.addOsc} subOsc={this.props.subOsc} oscArray={this.props.oscArray} />
<LfoPanel lfoRate={this.props.LFObj[2]} lfoFreq={this.props.LFObj[3]} onChange={this.props.changeLFO}
lfoType={this.props.LFObj[1]}/>
</div>
</div>
</div>
)
The LfoPanel component is designed much of the same way as the others...
Any pointers would be quite helpful, perhaps it is passing array elements as properties? If that is the case, that seems like a strange gotcha. Thank-you in advance...
Ok, so after some further research, I realized that it was in fact a mutability issue from Redux. Even though it was technically updating the state, it was not properly immutable. I ended up using the primary solution from this question.
Thanks to those who looked / took time to respond. Hopefully this reference will save another React-Redux a headache later on :)

Image handling with data input in path

I have an issue with my images in react. When i let the image render like this:
import road from '../../../../assets/images/icons/road.png';
<img src={road} />
It will work but i want it to be dynamic relying on the input of data.
So i tried it this way (where icon is refering to a data set resulting in road):
import road from '../../../../assets/images/icons/road.png';
...
render() {
const { place, date, icon, progress } = this.props.stage;
...
<img src={icon} />
So my guess is that there is an issue with referencing here. From my question you can understand that i am absolutely new to react. What i also noticed is that with the method above i will get an unused var error if i dont load this image. So for example i have a couple of these icons but depending on the data in the dataset it will only render a few. Which i find kind of messy.
I hope you can steer me towards the right direction. Kinda frustrating not being able to implement an image...
With this: Load images based on dynamic path in ReactJs
posted from Subham Khatri i was able to get the answer i desired.
<img src={require(`../../../../assets/images/icons/${icon}.png)`} />
As I understand you are trying to pass the image from this.props.stage. Did you first try console.log(icon). what do you see in the console window. First we need to know whether the data is being passed from props.

Extremely slow React list render

We are experiencing some frustrating issues with React.
We have a form, consisting from a search form and a search result list.
As seen below in the code. filter and content.
Whenever the user types in the search field, there is a debounce and a call to a rest service.
The result then populates the search result (content)
Even with as little as 15 items in the list, this is insanely slow.
it takes about 300 ms per update.
In production mode, there is no issue. only in dev mode.
Also, removing propTypes makes it much faster but still slow.
We can see that the ContactSearchResultLayout is being rendered 3 times per keystroke, while it really just should care about the result of the rest call.
What are our best bets here?
is the container component kind of pattern here wrong for our usecase, does it mean that if something in the SearchPageLayout props changes, the entire list will also be re-rendered?
We have a version that pretty much bypass React and just render item by item as they come in from the service call.
Which is super fast, but on the other hand, much less maintainable.
Is there some idiomatic way to make this work with React?
<SearchPageLayout
filter={
<ContactSearchForm
allTeams={allTeams}
allAreasOfExp={allAreasOfExp}
allResponsiblePeople={allResponsiblePeople}
allTags={allTags}
detailed={props.searchFormExpanded}
onSearchFieldBlur={() => props.setSearchFormExpanded(false)}
onSearchFieldFocus={() => props.setSearchFormExpanded(true)}
/>
}
content={
<ContactSearchResultLayout //<-- this rerenders too often
items={items.map(item => (
<ContactCard
key={item.PersonId}
areasOfExpertise={item.AreasOfExperise}
cellPhone={item.CellPhone}
city={item.City}
One reason for this as I see it, is that items is the result of a map operation and thus, causes a new array of components to be generated.
But how do we bypass this?
Thoughts?
Anonymous function will get rendered each time.
I'll create another method for creating the items:
getItems() {
return (
items.map(item => (
<ContactCard
key={item.PersonId}
areasOfExpertise={item.AreasOfExperise}
cellPhone={item.CellPhone}
city={item.City}
/>
)
)
}
<ContactSearchResultLayout
items={this.getItems()}
/>
How to check if props change and if you should re-render the code:
you can use react "shouldComponentUpdate"
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
componentWillUpdate(nextProps, nextState) {
//here you can compare your current state and props
// with the next state and props
// be sure to return boolean to decide to render or not
}

ReactJs Lazy loader

I'm new in ReactJs.
I need a lazy loader in my application when page is scroll down,
I'm using (https://jasonslyvia.github.io/react-lazyload/examples/#/normal?_k=rz3oyn)
Actually, this is working fine but first time it load all data.
I want to make api call and set data when page will scroll down.
Thank you.
Most probably what you need is an infinite scroll functionality. There are some good options for React when it comes to loading asynchronous data:
1) If you need high performance (a lot of results coming from the server) you can try react-infinite. As docs say:
React Infinite solves this by rendering only DOM nodes that the user
is able to see or might soon see.
2) Another simple option would be: react-infinite-scroller
General principle to make these libraries work is to pass their props which will let the module know when to make a request or when to wait.
<InfiniteScroll
pageStart={0}
loadMore={loadFunc}
hasMore={true || false}
loader={<div className="loader">Loading ...</div>}
>
{items} // <-- This is the content you want to load
</InfiniteScroll>
loadFunc will make an API call to the server and will set hasMore to false until it is successfully resolved.

Resources