Recharts stacked area show wrong yAxis labels? - reactjs

http://recharts.org/en-US/examples/StackedAreaChart
This example shows, and I also made pointers that the value of the values do not correspond to the label why is this happening?
Is there any explanation and how to fix it?

You can customize the tooltip using its content prop.
The component passed there receives the same props as the Rechart's Tooltip so you only need to override the needed and bypass the rest. If you don't want to change the visual part of tooltip you can return another Tooltip at the end.
// Do not pass the `content` since it causes a recursive rendering
const CumulativeTooltip = ({ content, payload, ...props }) => {
const values = payload.map(({ value }) => value);
const cumulativePayload = payload.reduce((result, item, index) => result.concat({
...item,
value: values.slice(0, index + 1).reduce((sum, v) => sum + v, 0)
}), []);
return (<Tooltip {...props} payload={cumulativePayload} />);
}
// ... later in chart
<Tooltip content={<CumulativeTooltip/>}/>
Playground

Related

How to get the width of an element using ref in react

I'm trying to get the width of an element, and to do this I'm using the following...
export default () => {
const { sidebarOpen } = useContext(AuthContext)
const containerRef = useRef()
const getWidth = () => myRef.current.getBoundingClientRect().width
const [width, setWidth] = useState(0)
console.log(sidebarOpen)
useEffect(() => {
const handleResize = () => setWidth(getWidth())
if(myRef.current) setWidth(getWidth())
window.addEventListener("resize", handleResize)
console.log('abc', myRef.current.offsetWidth)
return () => window.removeEventListener("resize", handleResize)
}, [myRef, sidebarOpen])
console.log(width)
return (
<div ref={containerRef}>
...
</div>
)
}
When the width of the screen is changed in dev tools page resize, it works fine, but when the value of sidebar changes from 'true' to 'false' (or vice-versa). It returns the previous value of the container width. Does anyone know what I'm doing wrong, I need to get the most up to date value of the container width every time it changes, whether this is caused by a change to 'sidebarOpen' or not.
By default, a div element takes the full width of its parent.
I guess you're using flexbox for the sidebar, so when it closes, the element that contains the content (not the sidebar) expands to the full width of the available space.
This might be the issue that you're facing.
The div with flexbox (on the left we have the Sidebar component and on the right the content):
And right now, when there is no Sidebar:
As another example, let's create a div that has no other property rather than backgroundColor:
Eg:
<div style={{backgroundColor: 'red'}}>Hello</div>
And the result:

How can I attach a react-tiny-popover Popover to an arbitraty element, instead of the child?

I have a complex grid in a React app, and I want to show details relating to a cell in a popover. I am using react-tiny-popover but my grid has many cells and a complex implementation, so the standard way of marking up the Popover is not feasible:
const DetailedCell = ({ details }) => <Popover content={details}> <Cell ... /> </Popover>; // Not feasible
Instead, I will keep track of the "target" cell that should currently have details displayed. How can I render a single Popover that is attached to the target cell and follows it around?
const DetailsPopover = () => undefined; // TODO how can this be implemented?
const MyPage = () => {
// ...
const [target, setTarget] = useState(null);
return <>
<ComplexGrid onSelectCell={setTarget} ... />
{target && <DetailsPopover target={target.domElement}>
Details of {getCellTitle(target)}: ...
</DetailsPopover>}
</>;
}
You can use the React.forwardRef to implement DetailsPopover using the react-tiny-popover v7 API, by passing an empty component to Popover that 'forwards' its ref to whichever element you want:
const RefTarget = React.forwardRef(({ target }, ref) => {
if (typeof ref === 'function') ref(target); // Forward target to callback refs.
else ref.current = target; // Forward target to object refs.
return null; // Don't render anything.
});
const TargetedPopover = ({ targetElement, children, ...props }) =>
<Popover isOpen={true} content={children} {...props}>
<RefTarget target={targetElement} />
</Popover>

How to trigger a cell change from within a component to update the grid data? (AG Grid - React)

I have a dropdown component within an Ag Grid. But when I change the value, the client-side data object doesn't change.
I'm triggering a function within the component when the dropdown is changed - but how can I tell the "parent" AG Grid to update it's data for that cell? (AG Grid automatically updates it's data when you're just changing text directly in a cell, not using a custom component.)
It seems to have something to do with using getValue(), but I can't seem to find the proper call in the documentation.
Are you using a Cell Renderer or Cell Editor to build the dropdown component?
If using a Custom Cell Editor, you must implement the getValue method otherwise the grid will not insert the new value into the row after editing is done.
See this implemented here:
const CustomCellEditor = forwardRef((props, ref) => {
const [selectedValue, setSelectedValue] = useState('United States');
const values = ['United States', 'Russia', 'Canada'];
/* Component Editor Lifecycle methods */
useImperativeHandle(ref, () => {
return {
getValue() {
return selectedValue;
},
};
});
const onChangeHandler = (event) => {
setSelectedValue(event.target.value);
};
return (
<div>
<select value={selectedValue} onChange={onChangeHandler}>
{values.map((item) => (
<option>{item}</option>
))}
</select>
</div>
);
});
Plunkr example
Documentation on Custom Cell Editors

How do you style the grouping rows when you group rows in React-Data-Grid?

Is it possible to style the grouping row that you can see in the attached screenshot? What I would like to do is provide a React component that is rendered in place of that.
Here is the codesandbox for the attached screenshot.
The screenshot shows that the class of the div that represents that grouping row is react-grid-row-group, and the only place this appears in the React-Data-Grid codebase is in RowGroup.tsx.
const RowGroup = forwardRef<HTMLDivElement, Props>(function RowGroup(props, ref) {
function onRowExpandToggle(expand?: boolean) {
const { onRowExpandToggle } = props.cellMetaData;
if (onRowExpandToggle) {
const shouldExpand = expand == null ? !props.isExpanded : expand;
onRowExpandToggle({ rowIdx: props.idx, shouldExpand, columnGroupName: props.columnGroupName, name: props.name });
}
}
function onRowExpandClick() {
onRowExpandToggle(!props.isExpanded);
}
function onClick() {
props.eventBus.dispatch(EventTypes.SELECT_CELL, { rowIdx: props.idx, idx: 0 });
}
const lastColumn = props.columns[props.columns.length - 1];
const style = { width: lastColumn!.left + lastColumn!.width };
const Renderer = props.renderer || DefaultBase;
return (
<div className="react-grid-row-group" style={style} onClick={onClick}>
<Renderer {...props} ref={ref} onRowExpandClick={onRowExpandClick} onRowExpandToggle={onRowExpandToggle} />
</div>
);
});
export default RowGroup;
So it seems that if that component receives a renderer prop, it will use it to render the group row under the div with aforementioned class name.
Usages of RowGroup.tsx are basically in Canvas.tsx, and Canvas instantiates RowGroup with the renderer prop being this.props.rowGroupRenderer. Canvas is rendered in Viewport.tsx. Viewport is rendered in Grid.tsx, and Grid is rendered in ReactDataGrid.
In the docs for React-Data-Grid we see the prop rowGroupRenderer described as
rowGroupRenderer
Function called whenever keyboard key is pressed down
type: func
However as described in the question above, looking at the code, we can see that this prop controls also what the row looks like when you have a group.
However, one question that remains is why this prop is not available in the TypeScript type definitions for the props of ReactDataGrid?

React Material-UI menu anchor broken by react-window list

I am using Material-UI and react-window in a project. My issue is, the material-ui menu component does not anchor to the element provided when that element is within a react-window virtualized list. The menu will appear in the upper left corner of the screen instead of anchored to the button that opens it. When using it all in a non-virtualized list, it works as expected. The menu properly anchors to the button that opens it.
Here's an example sandbox. The sandbox is pretty specific to how I'm using the components in question.
Any guidance on how I can resolve this?
Here's a modified version of your sandbox that fixes this:
Here was your initial code in BigList:
const BigList = props => {
const { height, ...others } = props;
const importantData = Array(101 - 1)
.fill()
.map((_, idx) => 0 + idx);
const rows = ({ index, style }) => (
<FancyListItem
index={index}
styles={style}
text="window'd (virtual): "
{...others}
/>
);
return (
<FixedSizeList
height={height}
itemCount={importantData.length}
itemSize={46}
outerElementType={List}
>
{rows}
</FixedSizeList>
);
};
I changed this to the following:
const Row = ({ data, index, style }) => {
return (
<FancyListItem
index={index}
styles={style}
text="window'd (virtual): "
{...data}
/>
);
};
const BigList = props => {
const { height, ...others } = props;
const importantData = Array(101 - 1)
.fill()
.map((_, idx) => 0 + idx);
return (
<FixedSizeList
height={height}
itemCount={importantData.length}
itemSize={46}
outerElementType={List}
itemData={others}
>
{Row}
</FixedSizeList>
);
};
The important difference is that Row is now a consistent component type rather than being redefined with every render of BigList. With your initial code, every render of BigList caused all of the FancyListItem elements to be remounted rather than just rerendered because the function around it representing the "row" type was a new function with each rendering of BigList. One effect of this is that the anchor element you were passing to Menu was no longer mounted by the time Menu tried to determine its position and anchorEl.getBoundingClientRect() was providing an x,y position of 0,0.
You'll notice in the react-window documentation (https://react-window.now.sh/#/examples/list/fixed-size) the Row component is defined outside of the Example component similar to how the fixed version of your code is now structured.
Ryan thanks for your answer! It helped me!
There is another solution:
Defining the parent component as a class component (not a functional component).
My problem was that I was calling the 'Rows' function like so:
<FixedSizeList
height={height}
itemCount={nodes.length}
itemSize={50}
width={width}
overscanCount={10}
>
{({ index, style }) => this.renderListItem(nodes[index], style)}
</FixedSizeList>
The fix was similar to what Ryan suggested:
render() {
...
return <FixedSizeList
height={height}
itemCount={nodes.length}
itemSize={50}
width={width}
overscanCount={10}
itemData={nodes}
>
{this.renderListItem}
</FixedSizeList>
}
renderListItem = ({data,index, style}) => {
...
}
I used the itemData prop to access the nodes array inside the renderListItem function

Resources