Using VirtualList, VirtualGridList and Scroller

This document describes VirtualList, VirtualGridList, and Scroller.

VirtualList/VirtualGridList

Basic usage of VirtualList and VirtualGridList

  • At least four props below are required to show a list properly.

    • data: Data for passing through to the component prop. For performance reason, changing this prop does NOT always cause the list to redraw its items.

    • dataSize: Size of the data. A list does not check the size of data prop. dataSize prop is the only value to count items in a list.

    • itemSize: Size of an item for the list. You will get an error when you build an app in dev mode without it. For the VirtualList, valid value is a number. For the VirtualGridList, valid value is an object that has minWidth and minHeight as properties.

    • component: The render function for an item of the list. The list does NOT always render a component whenever its render function is called due to performance optimization.

      • data is for accessing the supplied data property of the list. In most cases, it is recommended to use data from redux store instead of using this parameter due to performance optimizations.
      • data-index is required for Spotlight 5-way navigation. Pass to the root element in the component.
      • index is the index number of the component to render
      • key MUST be passed as a prop to the root element in the component for DOM recycling.
    • Example

      <VirtualList
      	component={this.renderItem}
      	data={data}
      	dataSize={data.length}
      	itemSize={ri.scale(72)}
      />
      
      <VirtualGridList
      	component={this.renderItem}
      	data={data}
      	dataSize={data.length}
      	itemSize={{minWidth: ri.scale(90), minHeight: ri.scale(135)}}
      />
      
  • If you want to provide spacing or other numeric properties, you have to specify them as a number surrounded by braces, not as a string by quotes.

    <VirtualList
    	component={this.renderItem}
    	data={data}
    	dataSize={data.length} //<-- numeric property
    	itemSize={ri.scale(72)} //<-- numeric property
    	spacing={ri.scale(10)} //<-- numeric property
    />
    

Common rules of Items for VirtualList/VirtualGridList

  • A renderer for an item should be specified in component prop in VirtualList as a function.

  • VirtualList passes data, index, data-index, and key to the component function.

  • Be sure you are passing {...rest} to the item component for reusing DOM.

  • VirtualList will automatically give proper className for items.

  • Be sure to compose className prop when you make customized item component.

  • Make sure you are not using an inline function for component.

  • If you want to scroll the list via 5-way navigation on the certain component in an item, you should pass data-index prop.

  • Example:

    //.js
    renderItem = ({data, index, ...rest}) => {
    	return (
    		<div {...rest}>
    			{data[index].name}
    		</div>
    	);
    }
    ...
    render = () => {
    	return (
    		<VirtualList
    			component={this.renderItem}
    			data={data}
    			dataSize={data.length}
    			itemSize={this.itemSize}
    		/>
    	);
    }
    
  • If you create a custom item, make sure you are passing props from parents (render function) to the child.

    //MyListItem.js
    const MyListItem = kind({
    	.....
    	render = (props) => { //<-- should pass props
    		return (
    			<div {...props}>
    				...
    			</div>
    		);
    	}
    });
    
    //app.js
    renderItem = ({data, index, ...rest}) => {
    	return (
    		<MyListItem index={index} {...rest} />
    	);
    }
    

Items for VirtualGridList

  • GridListImageItem components can be used as items of VirtualGridList. They have Moonstone styling applied and have a placeholder image as a background.

  • caption and subCaption are supported.

  • For showing Moonstone’s selection overlay, set selectionOverlayShowing to true. (default is false)

  • selected prop shows item’s status of selection.

  • source prop should be set to URL path. (e.g. source="http://XXXX/image.png" , source="../assets/image.png")

  • Example:

    renderItem = ({data, index, ...rest}) => {
    	const {text, subText, source} = data[index];
    	return (
    		<GridListImageItem
    			{...rest}
    			caption={text}
    			className={css.item}
    			source={source}
    			subCaption={subText}
    		/>
    	);
    };
    

Scroller

Basic usage of Scroller

  • Make sure you specify width and height of Scroller.

  • You can specify the scrollable direction with direction props. Valid values are both, horizontal, and vertical.

  • Example:

    //.less
    .scroller {
    	height: 550px;
    	width: 480px;
    }
    
    //.js
    <Scroller
    	className={css.scroller}
    	direction="both"
    >
    	<div className={css.content}>
    		Lorem ipsum dolor sit amet, consectetur adipiscing elit.<br />
    	</div>
    </Scroller>
    

Using scrollTo() method in VirtualList/VirtualGridList and Scroller

  • Prop cbScrollTo is a callback function.

    • VirtualList, VirtualGridList, and Scroller provide cbScrollTo prop which can be set to a callback function that will receive the scrollTo() method.
    • The callback function is called just once when a list or a scroller is created to prevent repeated calls when a list or a scroller is updated.
    • Do not change cbScrollTo prop after a list or a scroller is mounted. It does not have any effect.
  • The binding of a callback function

  • Example:

    class SampleApp extends React.Component {
    	constructor (props) {
    		super(props);
    
    		this.y = 0;
    	}
    	...
    	getScrollTo = (scrollTo) => { // callback function to get scrollTo method; arrow function (ES6) is recommended to make sure `this` binding.
    		this.scrollTo = scrollTo;
    	}
    	...
    	doSomething = () => {
    		...
    		this.scrollTo({position: {y: this.y + offset}, animate: true}); // call the function of SampleApp, not a list.
    	}
    	...
    	render = () => {
    		return (
    			<VirtualList
    				cbScrollTo={this.getScrollTo} // pass callback function
    				component={this.renderItem}
    				data={data}
    				dataSize={data.length}
    				itemSize={this.itemSize}
    			/>
    		);
    	}
    }
    
  • Example:

    this.scrollTo({position: {y: 100}, animate: false}); // scroll y position to 100px without animation
    this.scrollTo({position: {x: 100, y: 200}); // scroll to (100px, 200px) position; animation is enabled if omitted
    this.scrollTo({align: 'bottom'}); // scroll to the bottom
    this.scrollTo({align: 'lefttop'}); // scroll to the left top position; identical to {position: {x: 0, y:0}}
    this.scrollTo({index: 20}); // VirtualList/VirtualGridList only; scroll to the 21st item; index is counting from 0
    this.scrollTo({index: 20, focus: true}); // VirtualList/VirtualGridList only; scroll to the 21st item and focus on the item
    this.scrollTo({node: childNode}); // Scroller only; scroll to the child node.
    this.scrollTo({node: childNode, focus: true}); // Scroller only; scroll to the child node and focus on the node.
    

Event Callbacks for VirtualList, VirtualGridList, and Scroller

  • You can specify callback functions for scroll events.

  • When you scroll on a list or a scroller, onScrollStart, onScroll, and onScrollStop events fire.

  • Each event sends an object with scrollLeft, scrollTop, and moreInfo properties in it.

  • For VirtualList/VirtualGridList, moreInfo has firstVisibleIndex and lastVisibleIndex.

  • It is recommended not to call setState() in onScroll event callback.

  • Example:

    //app.js
    ...
    handlerOnScrollStart = () => {
    	this.setState({message: 'startScroll'});
    }
    handlerOnScroll = ({scrollTop}) => {
    	this.y = scrollTop;
    }
    handlerOnScrollStop = ({scrollTop}) => {
    	this.y = scrollTop;
    	this.setState({message: 'scrollStopped'});
    }
    ...
    render = () => {
    	return (
    		<VirtualList
    			...
    			onScrollStart={this.handlerOnScrollStart}
    			onScroll={this.handlerOnScroll}
    			onScrollStop={this.handlerOnScrollStop}
    		/>
    	);
    }