Hi!
When trying to render such construction
<div style={{flex: '1'}}>
<AutoSizer>
{
({height, width}) => (
<CellMeasurer
cellRenderer={this._cellRenderer}
columnCount={1}
rowCount={messages.size}
width={width}
>
{
({getRowHeight}) => (
<Grid
columnCount={1}
columnWidth={width}
height={height}
overscanColumnCount={0}
overscanRowCount={0}
cellRenderer={this._cellRenderer}
rowCount={messages.size}
rowHeight={getRowHeight}
width={width}
/>
)
}
</CellMeasurer>
)
}
</AutoSizer>
</div>
I get cryptic
invariant.js?4599:38 Uncaught Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).
When it should be unmounted I get
invariant.js?4599:38 Uncaught Invariant Violation: removeComponentAsRefFrom(...): Only a ReactOwner can have refs. You might be removing a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).
_this.cellRenderer looks as following:
_cellRenderer({ rowIndex }) {
"use strict";
let {messages, userId} = this.props;
const messagesArray = messages.toArray();
if (messagesArray.length === 0) {
return null;
}
const msg = messagesArray[rowIndex];
return (
<Message message={msg} id={userId}/>
);
}
Also for some reason only rows, which are visible on first render are rendered (so no new rows appear on scrolling)
Replacing my <Message/> component with <div>{message}</div> seems to fix this problem
But still, I'd like to use my component :)
However this issue pops up again when trying to render
<div>
<div>
{message}
</div>
</div>
Hi @wasd171. Unfortunately the current approach I'm following in CellMeasurer is a bit hackish. I've tried a couple of alternatives but haven't found any other approaches that work (that don't also require asynchronicity).
For what it's worth this same error occurs if you try to use CellMeasurer for a VirtualScroll or a FlexTable instead of just a Grid. It's the main reason I added the warning I did to the documentation.
Help would be appreciated here if others have ideas to contribute.
I've run into this show-stopper as well, trying to render a grid with a CellMeasurer.
Looking into it today, there are a couple things i can modify to make it work -- either remove the scrollingContainer ref from <Grid>, or remove the renderToString call in _measureCell. But it's still not clear to me how those are connected.
Obviously renderToString is being called on a component that is rendered outside of render() (the cell), resulting in a component that has no _owner, like the error says: "Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method". But nothing's trying to set a ref on that component, as far as i can tell.
What is getting a ref is the outer div of Grid (scrollingContainer). Removing that ref fixes the error. But I don't see why it should, since the Grid's render doesn't seem to be connected to the measuring process of CellMeasurer.
In any case, maybe these observations will help jumpstart someone else who can track down a fix for the issue.
I'm not able to reproduce this problem using CellMeasurer with VirtualScroll as I was initially able to but I can if I return a custom component (eg. the Message component above).
Setting a breakpoint in the React source it looks like the first few rows that are rendered have an owner that is a ReactCompositeComponentWrapper but the one that eventually errors has a null value for owner.
that squares with my experience, too -- i only see the error after the final row renders. Will lookagain from that angle and see if I can track anything down
BTW, would using CellMeasurer with VirtualScroll even be possible, given the difference in render fn signatures? (rowIndex vs index)
Yup, you just need to create an adapter function eg
function cellRender ({ rowIndex }) {
return rowRenderer({ index: rowIndex })
}
Or just rename inline
rowRenderer({ rowIndex: index }) {
// Function body here
}
mentioned this on gitter, but here's the relevant react issue for anyone interested:
https://github.com/facebook/react/issues/3344
I also found problem when using <Link> component from react-router5 in Grid inside CellMeasurer. But there I get different type of error in console:
Failed Context Types: Required context `router` was not specified in `WithRoute[BaseLink]`.
I don't get this problem before implementation of CellMeasurer
Cannot be source of this problem similar? We lose context. Unfortunately have no idea how to fix it (how to add right context again inside CellMeasurer).
nice i actually hacked a solution together without cellmeasurer before stealing a bit of code from it. Although it sets the row heights at predefined pixel heights. Still might be useful for someone who doesnt want to use cellmeasurer:
`
ref= {(ref) => {
this.autoSizer = ref;
}}
{({ width }) => {
if (this.autoSizer && this.mostRecentWidth !== this.autoSizer.state.width) {
const currentWidth = this.autoSizer.state.width;
if (currentWidth < 768) {
this.rowHeight = 209;
} else if (currentWidth > 768 && currentWidth < 1126) {
this.rowHeight = 137;
} else {
this.rowHeight = 90;
}
}
if (this.autoSizer) {
this.mostRecentWidth = this.autoSizer.state.width;
}`
Most helpful comment
I also found problem when using
<Link>component fromreact-router5inGridinsideCellMeasurer. But there I get different type of error in console:I don't get this problem before implementation of
CellMeasurerCannot be source of this problem similar? We lose context. Unfortunately have no idea how to fix it (how to add right context again inside
CellMeasurer).