| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: ReactJS | 
					
						
							| 
									
										
										
										
											2023-01-10 00:31:37 +00:00
										 |  |  | pagination_prev: demos/index | 
					
						
							|  |  |  | pagination_next: demos/mobile/index | 
					
						
							|  |  |  | sidebar_position: 1 | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [ReactJS](https://reactjs.org/) is a JS library for building user interfaces. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This demo tries to cover common React data flow ideas and strategies. React | 
					
						
							|  |  |  | familiarity is assumed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Other demos cover general React deployments, including: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | - [Static Site Generation powered by NextJS](/docs/demos/content#nextjs) | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | - [iOS and Android applications powered by React Native](/docs/demos/mobile/reactnative) | 
					
						
							|  |  |  | - [Desktop application powered by React Native Windows + macOS](/docs/demos/desktop/reactnative) | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | - [React Data Grid UI component](/docs/demos/grid#react-data-grid) | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Installation
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | [The "Frameworks" section](/docs/getting-started/installation/frameworks) covers | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | installation with Yarn and other package managers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The library can be imported directly from JS or JSX code with: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import { read, utils, writeFile } from 'xlsx'; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Internal State
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The various SheetJS APIs work with various data shapes.  The preferred state | 
					
						
							|  |  |  | depends on the application. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Array of Objects
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Typically, some users will create a spreadsheet with source data that should be | 
					
						
							|  |  |  | loaded into the site.  This sheet will have known columns.  For example, our | 
					
						
							|  |  |  | [presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 08:41:34 +00:00
										 |  |  |  | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This naturally maps to an array of typed objects, as in the TS example below: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```ts | 
					
						
							|  |  |  | import { read, utils } from 'xlsx'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | interface President { | 
					
						
							|  |  |  |   Name: string; | 
					
						
							|  |  |  |   Index: number; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | 
					
						
							|  |  |  | const wb = read(f); | 
					
						
							|  |  |  | const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]); | 
					
						
							|  |  |  | console.log(data); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `data` will be an array of objects: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | [ | 
					
						
							|  |  |  |   { Name: "Bill Clinton", Index: 42 }, | 
					
						
							|  |  |  |   { Name: "GeorgeW Bush", Index: 43 }, | 
					
						
							|  |  |  |   { Name: "Barack Obama", Index: 44 }, | 
					
						
							|  |  |  |   { Name: "Donald Trump", Index: 45 }, | 
					
						
							|  |  |  |   { Name: "Joseph Biden", Index: 46 } | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A component will typically map over the data. The following example generates | 
					
						
							|  |  |  | a TABLE with a row for each President: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  | ```jsx title="src/SheetJSReactAoO.js" | 
					
						
							|  |  |  | import React, { useCallback, useEffect, useState } from "react"; | 
					
						
							|  |  |  | import { read, utils, writeFileXLSX } from 'xlsx'; | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default function SheetJSReactAoO() { | 
					
						
							|  |  |  |   /* the component state is an array of presidents */ | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   const [pres, setPres] = useState([]); | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Fetch and update the state once */ | 
					
						
							|  |  |  |   useEffect(() => { (async() => { | 
					
						
							|  |  |  |     const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | 
					
						
							|  |  |  |     // highlight-start | 
					
						
							|  |  |  |     const wb = read(f); // parse the array buffer | 
					
						
							|  |  |  |     const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |     const data = utils.sheet_to_json(ws); // generate objects | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  |     setPres(data); // update state | 
					
						
							|  |  |  |     // highlight-end | 
					
						
							|  |  |  |   })(); }, []); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   /* get state data and export to XLSX */ | 
					
						
							|  |  |  |   const exportFile = useCallback(() => { | 
					
						
							|  |  |  |     // highlight-next-line | 
					
						
							|  |  |  |     const ws = utils.json_to_sheet(pres); | 
					
						
							|  |  |  |     const wb = utils.book_new(); | 
					
						
							|  |  |  |     utils.book_append_sheet(wb, ws, "Data"); | 
					
						
							|  |  |  |     writeFileXLSX(wb, "SheetJSReactAoO.xlsx"); | 
					
						
							|  |  |  |   }, [pres]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  |   return (<table><thead><th>Name</th><th>Index</th></thead><tbody> | 
					
						
							|  |  |  |     { /* generate row for each president */ | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  |       pres.map(pres => (<tr> | 
					
						
							|  |  |  |         <td>{pres.Name}</td> | 
					
						
							|  |  |  |         <td>{pres.Index}</td> | 
					
						
							|  |  |  |       </tr>)) | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   </tbody><tfoot><td colSpan={2}> | 
					
						
							|  |  |  |     <button onClick={exportFile}>Export XLSX</button> | 
					
						
							|  |  |  |   </td></tfoot></table>); | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### HTML
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The main disadvantage of the Array of Objects approach is the specific nature | 
					
						
							|  |  |  | of the columns.  For more general use, passing around an Array of Arrays works. | 
					
						
							|  |  |  | However, this does not handle merge cells well! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `sheet_to_html` function generates HTML that is aware of merges and other | 
					
						
							|  |  |  | worksheet features.  React `dangerouslySetInnerHTML` attribute allows code to | 
					
						
							|  |  |  | set the `innerHTML` attribute, effectively inserting the code into the page: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  | ```jsx title="src/SheetJSReactHTML.js" | 
					
						
							|  |  |  | import React, { useCallback, useEffect, useRef, useState } from "react"; | 
					
						
							|  |  |  | import { read, utils, writeFileXLSX } from 'xlsx'; | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default function SheetJSReactHTML() { | 
					
						
							|  |  |  |   /* the component state is an HTML string */ | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   const [__html, setHtml] = useState(""); | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   /* the ref is used in export */ | 
					
						
							|  |  |  |   const tbl = useRef(null); | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Fetch and update the state once */ | 
					
						
							|  |  |  |   useEffect(() => { (async() => { | 
					
						
							|  |  |  |     const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | 
					
						
							|  |  |  |     const wb = read(f); // parse the array buffer | 
					
						
							|  |  |  |     const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | 
					
						
							|  |  |  |     // highlight-start | 
					
						
							|  |  |  |     const data = utils.sheet_to_html(ws); // generate HTML | 
					
						
							|  |  |  |     setHtml(data); // update state | 
					
						
							|  |  |  |     // highlight-end | 
					
						
							|  |  |  |   })(); }, []); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   /* get live table and export to XLSX */ | 
					
						
							|  |  |  |   const exportFile = useCallback(() => { | 
					
						
							|  |  |  |     // highlight-start | 
					
						
							|  |  |  |     const elt = tbl.current.getElementsByTagName("TABLE")[0]; | 
					
						
							|  |  |  |     const wb = utils.table_to_book(elt); | 
					
						
							|  |  |  |     // highlight-end | 
					
						
							|  |  |  |     writeFileXLSX(wb, "SheetJSReactHTML.xlsx"); | 
					
						
							|  |  |  |   }, [tbl]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( <> | 
					
						
							|  |  |  |     <button onClick={exportFile}>Export XLSX</button> | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  |   // highlight-next-line | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     <div ref={tbl} dangerouslySetInnerHTML={{ __html }} /> | 
					
						
							| 
									
										
										
										
											2022-08-19 06:42:18 +00:00
										 |  |  |   </>); | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Rows and Columns
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Some data grids and UI components split worksheet state in two parts: an array | 
					
						
							|  |  |  | of column attribute objects and an array of row objects.  The former is used to | 
					
						
							|  |  |  | generate column headings and for indexing into the row objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The safest approach is to use an array of arrays for state and to generate | 
					
						
							| 
									
										
										
										
											2022-08-23 03:20:02 +00:00
										 |  |  | column objects that map to A1-Style column headers. | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | The [React Data Grid demo](/docs/demos/grid#rows-and-columns-state) uses this approach | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | with the following column and row structure: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* rows are generated with a simple array of arrays */ | 
					
						
							|  |  |  | const rows = utils.sheet_to_json(worksheet, { header: 1 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* column objects are generated based on the worksheet range */ | 
					
						
							|  |  |  | const range = utils.decode_range(ws["!ref"]||"A1"); | 
					
						
							|  |  |  | const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ | 
					
						
							|  |  |  |   /* for an array of arrays, the keys are "0", "1", "2", ... */ | 
					
						
							|  |  |  |   key: String(i), | 
					
						
							|  |  |  |   /* column labels: encode_col translates 0 -> "A", 1 -> "B", 2 -> "C", ... */ | 
					
						
							|  |  |  |   name: XLSX.utils.encode_col(i) | 
					
						
							|  |  |  | })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Legacy Deployments
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-30 05:45:37 +00:00
										 |  |  | [The Standalone Scripts](/docs/getting-started/installation/standalone) play nice | 
					
						
							| 
									
										
										
										
											2022-08-17 07:10:01 +00:00
										 |  |  | with legacy deployments that do not use a bundler. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [The legacy demo](pathname:///react/index.html) shows a simple React component | 
					
						
							|  |  |  | transpiled in the browser using Babel standalone library. |