I have component with navigation, on click item to child component passed in props some params, one of params - object 'itemImage' with className and url, like this:
{
url: '/static/image.svg',
className: 'absolute hidden md:block min-w-53 lg:min-w-68 mt-30 lg:mt-19 -ml-28 lg:-ml-75',
}
In child component ItemComponent:
{
itemImage &&
<img className={itemImage.className} src={itemImage.url} alt='' />
}
ItemComponent is selected from an array according to the order of the element in navigation (it is responsible for the object passed to the child component), since the list of navigation elements and elements of the array of pictures are not related and of different lengths. The sample is implemented on the basis of an index in map for objects and an index in an array with pictures, to be more precise.
Problem:
the pictures flicker as the state of the parent and the child is updated, is it possible to somehow avoid this and make the change of the picture clear without the flickering of the previous card.
You can use the below-mentioned code to render the Array of Images.
<>
{this.props.Images.map(item=>{
return (item)
})}
<p>
{JSON.stringify(this.state)}
</p>
<p>
{JSON.stringify(this.props.changed)}
</p>
<button onClick={this.props.onChange}>Change</button>
<button onClick={this.onCurrentChange}>Current State Change</button>
</>
Please check the demo here Demo
You can make somethings to try to prevent that.
1- Add a key prop to the elements. It help react understand that it is the same data from before and not re-render that piece.
2- Use react PureComponent on the flickering element https://reactjs.org/docs/react-api.html#reactpurecomponent to prevent the re-render
3 - Instead of purecomponent implement shouldComponentUpdate
Related
I have a main react component (The entire page) that contains several other UI items in it. One of those UI items is an OpenLayers map. Another component is a text field that contains the latitude and longitude of the current mouse pointer position.
I want the text field to update whenever the mouse pointer moves on the map. In my code's current state, this works.
The problem is every time the mouse moves and I update the react state value for the latitude/longitude (which gets rendered in the text field as expected) the map re-renders. This looks terrible because the map flashes every time as it begins to load the map tiles.
So I have the mouse latitude/longitude position, but I can't get the map to not flash/stutter/strobe.
Is there a way to get a mouse event from the map component, and send it to another component on the same screen without causing the render method to redraw the map every time? Or is React the wrong tool for this project?
As a note, I'm using React Redux to handle some state values, such as the map object. All of my child components are React functional components, but the main component for the page is a React class component.
If it helps, I set the mouse listener on the map like this:
this.props.map.on('pointermove', event => {
this.setState({
mouseCoordinates: (event.coordinate),
});
});
This is my render method:
render() {
return (
<div className="main">
<p className={noMargPad}>
{this.state.mouseCoordinates}
</p>
<Map
center={fromLonLat(this.state.center)}
zoom={this.state.zoom}
>
<Layers>
<TileLayer source={osm()} zIndex={0} />
{this.state.showLayer1 && (
<VectorLayer
source={vector({
features: new GeoJSON().readFeatures(geojsonObject, {
featureProjection: get("EPSG:3857"),
}),
})}
style={FeatureStyles.MultiPolygon}
/>
)}
{this.state.showMarker && (
<VectorLayer source={vector({
features: this.state.features
})} />
)}
</Layers>
<Controls>
<FullScreenControl />
</Controls>
</Map>
</div>
);
}
One of the main advantages of using a tool like React is it will only refresh the components in the render method that have had an update to their dependent data. See this article for more information.
The fact that your map is rendering again indicates that the map, or one of its children is being passed a piece of data that keeps changing.
Based on your code, one possibility is the call to OSM(), since that's a constructor from the OpenLayers API. A new object/class instance in JavaScript could cause data re-render.
The state for my project includes a list of nested animals eg:
{"europe":{"air":{name:"warbler", points:0}}}
My components are generated based on this data, and at the lowest level (the animal itself), there is a button which is currently triggering a series of callbacks to the highest level, starting a dispatch to the reducer. Every time a button is clicked, all the components from every continent re-render.
Would it be better to implement useContext, even though every level of component requires some amount of data from the state object?
I tried to implement useCallback, to prevent re-rendering but I didn't know which callbacks were causing it. What would be the best way to optimize rendering a series of nested components (without redux)?
Inside App component
{Object.entries(state.animalData).map(([continent, areas]) => (
<Continent
key={continent}
areas={areas}
totals={state.totals.continents[continent]}
handleVote={(
num: number,
animal: string,
area: string
) => triggerChange(num, animal, area, continent)}
/>
))}
Inside Continent component
<Area
key={area}
area={area}
animals={animals}
onVote={(num: number, animal: string) =>
handleVote(num, animal, area)
}
/>
Inside Area component
{animals.map(animal => (
<Animal
key={animal.name}
animal={animal}
voted={(num: number) => onVote(num, animal.name)}
/>
))}
Inside Animal component
<div>
<h4>{animal.name}</h4>
<div>
<button onClick={voted(+1)}> Upvote </button>
<button onClick={voted(-1)}> Downvote </button>
</div>
<h4>{`${animal.points} Points`}</h4>
<hr />
</div>
Your components trigger a re render because you are using inline defined functions everywhere and those aren't referentially stable. You can use the useCallback (https://reactjs.org/docs/hooks-reference.html#usecallback) hook to prevent re renders.
But you could also use a context provider (as you suggested) which holds the voted callback. That way you don't have to use prop drilling to get the function to the component where it is needed.
The basic solution for this is explained in detail here: https://medium.com/#jeromefranco/how-to-avoid-prop-drilling-in-react-7e3a9f3c8674
Can one React component render by 2 classes? Just like I did in the picture.
I tried the above. It gives me another error Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of "Groups".
The button component Im using in Groups method(Groups.jsx) like this way.
const Groups = (props) => (
<div className = 'panel'>
<h2>Groups</h2>
<button >Get Groups</button>
<div className = 'group-list'>
{props.groups.map((group) =>
<GroupsEntry name = {group.name}
members = {group.members}/>
)}
</div>
</div>
);
Do you guys have any idea about this? Thank you
I will try to clarify a little.
You can render a component from whatever parent component you want.
By in the case of your picture, what is telling you that the first component in tree, was App.js, and then App.js rendered Groups.js component, and Groups.js rendered your actual component.
In the same page, the warning you are seeing about using "key" is because you need to set a unique key value for each element that you are rendered as a list, a repeated item. This is because the internal react work to compare if it has to rerender again your component needs it. You will have performance problems (not in an easy example...) if you dont add it. Normally you use the id of the object you are rendering.
I hope i clarified a little.
Yes, a component can be rendered as many times as you would like. The issue is that you are mapping over an array and returning an element. React requires that you put a unique key prop on these elements that ideally are consistent between renders.
You can try to update your code to be something like the following:
const Groups = props => (
<div className="panel">
<h2>Groups</h2>
<button>Get Groups</button>
<div className="group-list">
{props.groups.map(group => (
<GroupsEntry key={group.name} name={group.name} members={group.members} />
))}
</div>
</div>
);
This is assuming group.name is unique. If you have a unique identifier (eg: group.id) that would be ideal.
For more examples and why this is necessary you can checkout the official docs: https://reactjs.org/docs/lists-and-keys.html
I'm making an app where I have an Overlay component and a Map component rendering behind it just like this:
<div>
{showOverlay && <Overlay />}
<Map /> // this component should mount once
</div>
The overlay is shown to let the map load underneath but when I remove the Overlay (set showOverlay to false here) the Map component re-load.
At first I thought the Map component was just re-rendering, but after some digging I discovered that the component was actually re-mounting.
If I log in the componentWillMount, componentWillUnmount and render methods, the log appear in that order (which seems contradictory)
render
willUnmount
willMount
The parent does not re-mount, only the Map component do.
The Map component just render a div that reference a mapbox-gl-js map (like this https://gist.github.com/tristen/5c4b346ae38892f732504e6785d87057#file-map-js)
What can cause my component to re-mount itself like that ?
Thanks !
I am reading React documentation and I have following two queries about child reconciliation.
Following link says that when children are deleted, instead of deleting them, they can be hidden with display set to 'none'. The specific sentence is:
"In most cases, this can be sidestepped by hiding elements instead of destroying them"
Who is supposed to sidestep? Does React do it automatically or does the programmer have to indicate to React framework to set display style to 'none' instead of reusing it?
(Link: https://facebook.github.io/react/docs/multiple-components.html#stateful-children)
Following link says that in case of reordered children, React can be informed to avoid unnecessary node deletes by assigning a key to each child. However, these keys should be assigned to the component and not to HTML container. But example before that shows assigning key to HTML container which is <li> in that case. What am I missing here?
(Link: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)
This is explicit on the part of the programmer. You should program the component to set a dynamic style to hide the element if you want this behavior, as per the example:
// Render Pass 1
<Card>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
// Render Pass 2
<Card>
<p style={{display: 'none'}}>Paragraph 1</p>
<p>Paragraph 2</p>
</Card>
You should put the key on the top-level element or component returned from the map function. In this example, it's the li:
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
In this example, it's the component that renders the li.
{this.props.results.map(function(result) {
return <ListItemWrapper key={result.id} data={result}/>;
})}