Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scrollToIndex will not SSR the specified index. #587

Closed
viqh opened this issue Feb 21, 2017 · 7 comments
Closed

scrollToIndex will not SSR the specified index. #587

viqh opened this issue Feb 21, 2017 · 7 comments

Comments

@viqh
Copy link

viqh commented Feb 21, 2017

Hi All,

First of all thank you for such a great component!

Recently tried to SSR the { List } component and could not server side the specific index.
This is the code (a small POC) that I'm running.

App.js

import React, { Component } from 'react';
import { List } from 'react-virtualized';

const generateImgs = (n) => {
  let imgs = [];

  for (let i = 0; i < n; i++) {
    const imgHeight = i > 9 ? `8${i}` : `80${i}`;
    const imgUrl = `http://placehold.it/800x${imgHeight}`;
    const styles = { height: `${imgHeight}px`, border: '1px solid black' };

    imgs.push({
      img: <img key={i} src={imgUrl} style={styles} alt={`${imgHeight}`} />,
      height: imgHeight,
    });
  }
  return imgs;
};

export default class App extends Component {
  constructor(props) {
    super(props);

    this.list = [...generateImgs(100)];
  }

  static defaultProps = { goToIndex: 0 };

  rowRenderer = ({ key, index, isScrolling, isVisible, style }) => {
    return (
      <div
        key={key}
        style={style}
      >
        {this.list[index].img}
      </div>
    );
  };

  getRowHeight = ({ index }) => {
    return parseInt(this.list[index].height, 10);
  };

  render() {
    const { goToIndex } = this.props;

    return (
      <div style={{ width: '800px', margin: '0 auto' }}>
        <List
          height={700}
          overscanRowCount={3}
          rowCount={this.list.length}
          rowHeight={this.getRowHeight}
          rowRenderer={this.rowRenderer}
          scrollToIndex={goToIndex}
          width={800}
        />
      </div>
    );
  }
}

server.js

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './app/App';
import template from './template';
const PORT = 3333;

const server = express();

server.use('/assets', express.static('assets'));

server.get('/', (req, res) => {
  const initialState = {
    goToIndex: 50
  };

  const appString = renderToString(<App {...initialState} />);
  console.log('appString = ', appString);

  res.send(template({
    body: appString,
    initialState: JSON.stringify(initialState)
  }));
});

server.listen(PORT);
console.log(`Listening on http://localhost:${PORT}`);

SSR output "appString ="

<div data-react-checksum="-2055938337" data-reactid="1" data-reactroot="" style="width:800px;margin:0 auto;">
	<div aria-label="grid" class="ReactVirtualized__Grid ReactVirtualized__List" data-reactid="2" role="grid" style="box-sizing:border-box;direction:ltr;height:700px;position:relative;width:800px;-webkit-overflow-scrolling:touch;will-change:transform;overflow-x:hidden;overflow-y:auto;" tabindex="0">
		<div class="ReactVirtualized__Grid__innerScrollContainer" data-reactid="3" style="width:auto;height:6086px;max-width:800px;max-height:6086px;overflow:hidden;pointer-events:;">
			<div data-reactid="4" style="height:800px;left:0;position:absolute;top:0;width:100%;"><img alt="800" data-reactid="5" src="http://placehold.it/800x800" style="height:800px;border:1px solid black;"></div>
			<div data-reactid="6" style="height:801px;left:0;position:absolute;top:800px;width:100%;"><img alt="801" data-reactid="7" src="http://placehold.it/800x801" style="height:801px;border:1px solid black;"></div>
			<div data-reactid="8" style="height:802px;left:0;position:absolute;top:1601px;width:100%;"><img alt="802" data-reactid="9" src="http://placehold.it/800x802" style="height:802px;border:1px solid black;"></div>
			<div data-reactid="10" style="height:803px;left:0;position:absolute;top:2403px;width:100%;"><img alt="803" data-reactid="11" src="http://placehold.it/800x803" style="height:803px;border:1px solid black;"></div>
		</div>
	</div>
</div>

As you can see from the output the 50th element was not SSR.

Is this expected behaviour?

Let me know if you need more info.

Thank you!

@bvaughn
Copy link
Owner

bvaughn commented Feb 21, 2017

react-virtualized reacts to changes in scroll offset by rendering the appropriate items. Convenience props like scrollToIndex trigger a scroll position adjustment which List then reacts to by rendering new cells.

This doesn't work in a SSR context because there is no UI (yet) to scroll. A List rendered with an initial scrollToIndex property adjusts offsets in componentDidMount since this is the first time a DOM element exists to scroll. This callback doesn't get triggered on the server (obviously) so that adjustment is deferred until the component is mounted in the browser.

@viqh
Copy link
Author

viqh commented Feb 21, 2017

@bvaughn Thx for quick reply! Now it's clear, it makes sense!

Thanks

@viqh
Copy link
Author

viqh commented Feb 21, 2017

@bvaughn Based on what the component is doing so far, how is easy would it be to add a prop such as preloadIndex or goToIndex ? Any idea?

Thanks

@bvaughn
Copy link
Owner

bvaughn commented Feb 21, 2017

Not sure. If you would like to investigate and submit a PR, feel free. 😄

@viqh
Copy link
Author

viqh commented Feb 21, 2017

@bvaughn Thanks! Will investigate!

@mbrevda
Copy link
Contributor

mbrevda commented Mar 1, 2017

Let's continue this in a PR, or reopen if further discussion is needed!

@mbrevda mbrevda closed this as completed Mar 1, 2017
@bvaughn
Copy link
Owner

bvaughn commented Mar 1, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants