Recharts stacked barchart order and legend are inconsistent - reactjs

I'm making a figure with ReCharts in ReactJS. In stacked bar chart, legend order is not consistent with vertical bar chart. Bar chart order should be from the top to the bottom to be consistent with legend. Does anyone know a workaround to fix it?
I have tried to change order of Legend by adding className to <Legend />, but it didn't work. className isn't general props? It has ul and li, so I am happy if I can change ul and li's style to reverse order.
official example: https://recharts.org/en-US/examples/StackedBarChart
issue: https://github.com/recharts/recharts/issues/209
jsfiddle: http://jsfiddle.net/j8csfvh1/12

In this case you can render a custom legend with a you're custom structure (html and css) and based on payload value using the prop content, here is the documentation :
https://recharts.org/en-US/api/Legend#content
Here is an adaptation of your code, it needs just some enhancement in term of css:
http://jsfiddle.net/tahalz/9427x1m8/
const renderLegend = (props) => {
const { payload } = props;
console.log(payload)
return (
<div>
{
payload.reverse().map((entry, index) => (
<span key={`item-${index}`}><div style={{display:'inline-block',width:'12px',height:'12px',backgroundColor:entry.color}}></div>{entry.value}</span>
))
}
</div>
);
}
...
<Legend content={renderLegend}/>

Related

React-material-ui-carousel not rendering full-height content on init

I am using react-material-ui-carousel v3 with MUI v5. I need to render custom HTML content inside the carousel. The problem I have is that on the first render the first item does not have full height, see images below
return (
<Carousel autoPlay={true}>
{items.map((item, i) => {
const htmlContent = getHtmlContent(decodeHtml(item));
return <div key={i}>{htmlContent}</div>;
})}
</Carousel>
);
First init
After moving to the second page and then to the first page
How can I adjust the height so it shows the full height of the content?

Display tooltip with diferent values for each bar using recharts

I have a chart and I want to display a tooltip for each bar with its data.
I used this example from their documentation https://recharts.org/en-US/examples/CustomContentOfTooltip
I created a custom tooltip element
const CustomTooltip = ({ active, payload }: TooltipProps<number, string>) =>{
console.log(payload)
if (active) {
return (
<div className="custom-tooltip">
{payload && payload[0] &&
<p className="label">{`${payload![0].name}: ${payload![0].value}`}</p>
}
</div>
);
}
return null;
};
and this is bar chart element where I use the custom tooltip as in the example above.
<BarChart>
...
<Tooltip cursor={false} content={<CustomTooltip />} />
{Object.values(dataKeyBar).map(({chart, color}, index) => {
return <Bar
radius={barSize}
key={`bar-${index}`}
barSize={barSize}
dataKey={chart}
fill={color}
/>
})}
</BarChart>
My problem is no matter what bar I'm hovering, I get the same data in my tooltip -
{`${payload![0].name}: ${payload![0].value}`}
the payload looks like this:
what I have tried to display different data in the tooltip for each bar is for the customTooltip but the tooltip is not showing at all.
{payload && payload.map((bar: any) => {
return <div className="custom-tooltip"><p className="label">{`${bar.name}: ${bar.value}`}</p></div>
})}
How can I display a tooltip with different data for each bar?
From what i'm seeing right now you are locating the Custom Tooltip component outside of map, so no matter where you hover over you'll get the same result sure, did you try to call it inside map ?

Dropdown menu flip position issue. React-Select + Material-UI Popper

I use the example autocomplete field from the Material-UI lib documentation. (https://material-ui.com/demos/autocomplete/#react-select)
There is a problem with fliping the menu when it opens at the bottom of the page or the browser's viewport.
Is there a way to fix this problem with Material-UI and react-select?
Or do I need to write something custom?
If you are not using a <Menu/> custom component, you can use the menuPlacement="auto" prop of <Select/>, then your problem is solved.
const components = {
Control,
// Menu , <-- delete it
NoOptionsMessage,
Option,
Placeholder,
SingleValue,
ValueContainer
};
https://github.com/JedWatson/react-select/issues/403
Otherwise you can choose another selector, material-ui provides 2 more differents integration with the <Popper/> component: react-autosuggest and downshift.
https://material-ui.com/demos/autocomplete/
Hope it helps!
i've faced the same problem, for <Select /> component i have used what TomLgls suggest, but for <AsyncSelect /> as a work-around, i used some offset calculations in my component :
const rootHeight = document.getElementById('root').offsetHeight ;
const selectElement = document.getElementById('async_select_container_id');
const selectOffsetBottom= selectElement.offsetHeight + selectElement.offsetTop;
...
<AsyncSelect
{...listProps}
menuPlacement={
rootHeight - selectOffsetBottom > 210 ? 'auto' : 'top' // react-select menu height is 200px in my case
}
/>
i hope it helps as well
If you have created customMenu component then in that give className as open-menu-top and write this code for class:
.menu-open-top {
top: auto;
bottom: 100%;
}
Your CustomMenu maybe look like this:
const CustomMenu = ({ children, innerProps, innerRef, selectProps }) => {
return (
<div
ref={innerRef}
{...innerProps}
className={`rs-menu ${customMenuClass} open-menu-top`}
>
{Your Logic}
</div>
);
};

ReactJs - Conditional Rendering or hiding component

What's the de facto approach to choosing between conditional rendering or hiding the component with { display: 'none' }?
For the sake of discussion, let's say that I have a FilterComponent that holds the title of the filter, and a list of FilterItems, with name and amount.
In short, a FilterComponent could be:
Color
Blue (19)
Yellow (17)
Orange (3)
Black (7)
Green (10)
+ Show More
When hitting Show More button, more FilterItems will be displayed, i.e.
Color
Blue (19)
Yellow (17)
Orange (3)
Black (7)
Green (10)
Brown (17)
Pink (88)
White (55)
Red (32)
Purple (17)
- Show Less
Should I hide the FilterItems that are below the Show More? Or should I return null for those below and render them after updating the state with Show More?
I think there are a few ways to accomplish what you need. However, this seems to be the most practised:
{myConditionIsTrue && <MyComponent />}
In your case, it makes sense to use state. I would have a prop inside FilterComponent called showFullList
{this.state.showFullList && (
<React.Fragment>
<All/><The/><Other/><Components/>
</React.Fragment>)}
Just be weary, this mechanism is actually removing/adding to the DOM.
Generally in React it is better to not render something than to render it as hidden. Here is one related discussion:
https://discuss.reactjs.org/t/conditional-rendering-or-toggling-hidden-classes/2535/6
I would go for the "updating state" approach. That way you always have the actual filterItems that is showing in the state. So your components state is in sync and represents the current UI that is showing.
Guess there's no right or wrong in this question though =)
It would make more sense to not render the items that should not be shown until after the Show More has been clicked, and the state has updated. This way you can handle how many items should be shown by default before clicking Show More. This way instead of applying inline styles, or a special class to certain elements, you can use the exact same logic to all FilterItems, but only render X of them.
You can change initial state value of isHidden or something like that . When you click button value will be oppasite of before situtation . And when you wants to render you should give condition ;
{ isHidden &&
...
Generally, there is no significant performance differences between display: none and conditional rendering, because the browser's behaviour in both cases is nearly the same. The main difference is that if you use display: none, then node is not removing from the DOM tree, which forces some CSS pseudo-selectors like :last-child to consider a hidden node as last-child and so on. So, it is not performance-related, but mostly CSS-related. Both of approaches are ok for use, I suppose :)
My prefer two methodes:
#1 Element Variables
const button = <LogoutButton onClick={this.handleLogoutClick} />;
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
2# Inline If with Logical && Operator
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
More details here: https://reactjs.org/docs/conditional-rendering.html
An other approach based on Array.prototype.slice() method
The usage in parent component
import React from "react";
import { ColorList } from "./Color";
export default function App() {
return <ColorList colors={["red", "green", "blue"]} visibleItemsCount={1} />;
}
And the ColorList component looks like this:
import React from "react";
// This is just a placeholder component :)
function Color({ color }) {
return <div style={{ color }}>{color}</div>;
}
export function ColorList({ colors, visibleItemsCount = 0 }) {
const [showMore, setShowMore] = React.useState(false);
// Toggle value on click button
const onClick = () => setShowMore((value) => !value);
// Memoize the color list when props changed
const visibleColors = React.useMemo(() => {
// If show more items, return the whole array
// Otherwise, return a sliced array based on visible items
const count = showMore ? colors.count : visibleItemsCount;
return colors.slice(0, count);
}, [colors, visibleItemsCount, showMore]);
console.log(visibleColors);
return (
<>
<h1>Color list</h1>
<>
{visibleColors.map((color) => (
<Color key={color} color={color} />
))}
</>
<button onClick={onClick}>{showMore ? "Show less" : "Show more"}</button>
</>
);
}
Note: I uploaded the code on CodeSandbox, you can check it here
You could use a library called react-if. This library helps you wether to render or not based on a a condition.
Here is an example:
const Bar = ({ name, age, drinkingAge }) => (
<div>
<Header />
<If condition={ age >= drinkingAge }>
<Then><span className="ok">Have a beer, {name}!</span></Then>
<Else><span className="not-ok">Sorry, {name}, you are not old enough.</span></Else>
</If>
<Footer />
</div> )

Sticky headers in react-virtualized

I am using a List component in react-virtualized to render a large number of items. In my implementation, the items are sectioned, and I want the section headers to be sticky so that the current section remains visible as users scroll down. Essentially, I need react-virtualized NOT to destroy the section headers as the scroll position changes (but continue to destroy other items). Is there any way to do this right now? I'm open to hacks as long as they aren't too crazy.
We had similar requirements to you - we need a list that was sectioned with support for sticky headers. We could not achieve this with react-virtualized Lists/Grids, so I created https://github.com/marchaos/react-virtualized-sticky-tree which supports sticky headers.
See example here.
If I understood your question correctly, you would like to have sticky header a la a spreadsheet. You can do that with the ScrollSync component, have a look at the demo/docs.
Here is the example displayed in docs:
import { Grid, List, ScrollSync } from 'react-virtualized'
import 'react-virtualized/styles.css'; // only needs to be imported once
function render (props) {
return (
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => (
<div className='Table'>
<div className='LeftColumn'>
<List
scrollTop={scrollTop}
{...props}
/>
</div>
<div className='RightColumn'>
<Grid
onScroll={onScroll}
{...props}
/>
</div>
</div>
)}
</ScrollSync>
)
}
In case anyone came here using react-virtualized's Table component instead of the List component, you can make the header sticky with the following CSS:
.ReactVirtualized__Table__headerRow {
position: sticky;
inset-block-start: 0;
z-index: 1;
}
Make sure none of the Table's parent elements have overflow styling, otherwise this won't work.

Resources