Does react-virtualized work with airbnb/enzyme? - react-virtualized

Is it possible to use react-virtualized and enzyme together? When I try to use them together I seem to get an empty list of items in the grid.

The 2 should work together, yes. I believe the likely problem is that the react-virtualized component is being given a width or height of 0 which causes it not to render anything. (It only renders enough to fill the "window" it has.)
Assuming you're using the AutoSizer HOC- (most people do)- then one pattern I've found helpful is to export 2 versions of components- one that expects explicit width/height properties and one that wraps the other with an AutoSizer. Pseudo code would be:
import { AutoSizer, VirtualScroll } from 'react-virtualized'
// Use this component for testing purposes so you can explicitly set width/height
export function MyComponent ({
height,
width,
...otherProps
}) {
return (
<VirtualScroll
height={height}
width={width}
{...otherProps}
/>
)
}
// Use this component in your browser where auto-sizing behavior is desired
export default function MyAutoSizedComponent (props) {
return (
<AutoSizer>
({ height, width }) => (
<MyComponent
height={height}
width={width}
{...props}
/>
)
</AutoSizer>
)
}

as of react-virtualized 9.12.0 the Autosizer has defaultWidth and defaultHeight properties.
I found setting those meant enzyme tests ran correctly - rendering the child rows as expected.
<AutoSizer disableHeight defaultWidth={100}>
{({ width }) => (
....
)}
</AutoSizer>

Putting this in my test case worked for me:
import { AutoSizer } from 'react-virtualized';
// ...
it('should do something', function() {
spyOn(AutoSizer.prototype, 'render').and.callFake(function render() {
return (
<div ref={this._setRef}>
{this.props.children({ width: 200, height: 100 })}
</div>
);
});
// do something...
I use Jasmine's spyOn here, but other libraries have their own ways of overwriting functions.
Keep in mind that this is pretty fragile against future changes to the react-virtualized library (this._setRef was just yanked from the source code), and may give you false positives.

Related

react-virtualized share CellMeasurerCache for multiple Grids

I got few grids side by side, and for first of them i want to calculate row heights dynamically using CellMeasurer, how it's possible to reuse CellMeasurerCache from this grid in another (to synchronize cell heights/widths)?
jsbin example
class App extends React.Component {
constructor(props) {
super(props);
this.leftHeadersCellMeasurerCache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 40
});
}
render() {
return (
<ScrollSync>
{({scrollTop, onScroll}) => (
<div className="row">
<LeftGrid
width={300}
height={500}
scrollTop={scrollTop}
cellMeasurerCache={this.leftHeadersCellMeasurerCache}
/>
<DataGrid
width={400}
height={500}
onScroll={onScroll}
rowHeight={this.leftHeadersCellMeasurerCache.rowHeight}
/>
</div>
)}
</ScrollSync>
)
}
}
PS. Unfortunately cannot use MultiGrid, data on left side is "uneven".
You can't directly share a CellMeasurerCache cache between Grids unless the content of all cells in both Grids are the same (which I doubt is ever the case).
I think you'll want to decorate the CellMeasurerCache in a similar way as MultiGrid does. Your decorator would need to decide when to pass-thru values as-is and when to add a column-offset to avoid clobbering measurements.

React Virtualized windowscroller scrollElement not working

You were right that I was not passing the props in correctly. Now I have it set up as such:
Container.jsx
<div className='container' ref={(ref) => {this.foo = ref;}}>
this.renderContainer()
</div>
<Section scrollContainer={this.foo}/>
Section.jsx (just passing down props)
<Panel scrollContainer={this.props.scrollContainer}/>
Section.propTypes = { scrollContainer: PropTypes.object.isRequired }
Panel.jsx (Passing down props)
<RenderedTable scrollContainer={this.props.scrollContainer} />
RenderedTable.jsx
return (
<div className='padding-top-20 font-smoothing'>
<WindowScroller scrollElement={this.props.scrollContainer}>
{({ height, isScrolling, scrollTop, onChildScroll }) => (
<AutoSizer disableHeight>
{({ width }) => (
<Table
Unfortunately the windowScroller still does not resize. I also dont get any warnings or errors. Do you use css tricks to get the scroller to resize? I see that in the example https://bvaughn.github.io/react-virtualized/#/components/WindowScroller
you change the flex and overflow properties when changing the scrollElement from window to scrollingBody.
I know you are very busy and greatly appreciate your help!
In your example, you've assigned the scroll ref to this.tabsContainer but you're trying to access it as this.props.tabContainer. Either this is your mistake, or the example is incomplete and more context is needed. :) Can you provide a Plnkr?

Styled Components - why does prop position affect styling?

I'm using styled-components to style a parent and child element in a component:
function StyledDemo({
name,
light,
...props
}) {
return (
<Parent {...props}>
<Child>{name}</Child>
</Parent>
);
}
I have a light prop which is true/false - but I'm having an issue with styling the elements based on the value of that property:
const Parent = styled.div`
background-color: #000;
width: 100%;
${props => props.light && `
background-color: #ccc;
`}
`;
The styling only seems to work when I remove the prop being passed into the function individually.
Parent element uses correct styling based on light prop value when:
function StyledDemo({ name, ...props })
Parent element does NOT use correct styling based on light prop value when:
function StyledDemo({ name, light, ...props })
I can get it all working by setting the prop on the Parent and Child component, but this doesn't seem like it's the best way:
return (
<Parent {...props} light={light}>
<Child light={light}>{name}</Child>
</Parent>
);
Is this the correct way to apply styles to components based on props, or is there an issue with my approach?
I have a demo to tinker with if it helps:
https://www.webpackbin.com/bins/-Kfcsujw99cjU7ttqgTz
This is not related to styled-components but to the rest parameter.
When you do the rest operator, any property you "pick" out by name won't be contained in the ...rest variable. So when you do
const Button = ({ light, ...rest }) => ()
<Button light primary />
rest will only contain the primary property, but not light, that's now it's own variable.
If you did
const Button = ({ ...rest }) => ()
<Button light primary />
instead rest would also contain light.
So in your example, you're picking out light from ...props, so when you pass {...props} on to the parent it doesn't contain light anymore, so styled-components doesn't know it exists! Either you go with your first version, or you have to manually apply it to each component.
See MDN for more information about the rest parameter!

autosizer scrollsync grid combi scrollwidth not updated

I am trying to use an <ScrollSync> with an embedded <AutoSizer> like this:
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => {
<AutoSizer onResize={this.onResize}>{
({ width, height }) => (
<Grid {...alltheprops} onScroll={onScroll}/>
)
}</AutoSizer>
}
</ScrollSync>
This is of course greatly simplified but will get my point across (I hope). So the onScroll of the grid is connected to the scrollsync. My problem is that whenever the autoresizer triggers because I made my window wider the scrollSync will not be notified of the new scrollWidth. Any idea how to fix this?

Warning when react virtualized column is subclassed

When I inherit/subclass the 'Column' component, it throws Warning: Failed prop type: Table only accepts children of type Column
This is how I subclassed Column
import React, {Component, PropTypes} from 'react';
import * as RV from 'react-virtualized';
class Column extends Component {
constructor() {
super();
}
render() {
return (
<RVC.Column {...this.props} type="Column" />
)
}
}
Column.defaultProps = RV.Column.defaultProps;
Column.propTypes = RV.Column.propTypes;
export default Column;
It works very well but how can I avoid from that warning?
I don't think there's any benefit to subclassing Column. I assume your real intent is to set default values or DRY up your project in which case, I'd suggest just using a factory-function for columns like so:
import { Column, Table } from 'react-virtualized'
export default function CustomColumn (columnProps) {
const customProps = {
// Set any default props here ...
}
return (
<Column
{...customProps}
{...columnProps}
/>
)
}
function ExampleTable (tableProps) {
return (
<Table {...tableProps}>
{CustomColumn({
dataKey: 'foo',
width: 100
})}
{CustomColumn({
dataKey: 'bar',
width: 100
})}
</Table>
)
}
For what it's worth, I've done this on Production projects and it works nicely. If you think you have a strong use-case for subclassing Column though let me know and I will consider adding support for it.
I'm afraid you are not subclassing RV.Column at all, you are still subclassing React.Component, just that the name of your component is Column. React will still show the error because your self-defined Column !== RVC.Column.
Why do you want to subclass it in the first place? What does type="Column" do?

Resources