forked from sheetjs/docs.sheetjs.com
		
	rn
This commit is contained in:
		
							parent
							
								
									5f52a9f6b6
								
							
						
					
					
						commit
						74ac713193
					
				| @ -1,5 +1,7 @@ | ||||
| --- | ||||
| title: React Native | ||||
| sidebar_label: React Native | ||||
| description: Build data-intensive mobile apps with React Native. Seamlessly integrate spreadsheets into your app using SheetJS. Securely process and generate Excel files in the field. | ||||
| pagination_prev: demos/static/index | ||||
| pagination_next: demos/desktop/index | ||||
| sidebar_position: 1 | ||||
| @ -7,13 +9,26 @@ sidebar_custom_props: | ||||
|   summary: React + Native Rendering | ||||
| --- | ||||
| 
 | ||||
| # Sheets on the Go with React Native | ||||
| 
 | ||||
| import current from '/version.js'; | ||||
| import Tabs from '@theme/Tabs'; | ||||
| import TabItem from '@theme/TabItem'; | ||||
| import CodeBlock from '@theme/CodeBlock'; | ||||
| 
 | ||||
| The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported | ||||
| from the main `App.js` entrypoint or any script in the project. | ||||
| [React Native](https://reactnative.dev/) is a mobile app framework. It builds | ||||
| iOS and Android apps that use JavaScript for describing layouts and events. | ||||
| 
 | ||||
| [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing | ||||
| data from spreadsheets. | ||||
| 
 | ||||
| This demo uses React Native and SheetJS to process and generate spreadsheets. | ||||
| We'll explore how to load SheetJS in a React Native app in a few ways: | ||||
| 
 | ||||
| - ["Fetching Remote Data"](#fetching-remote-data) uses the built-in `fetch` to | ||||
| download and parse remote workbook files. | ||||
| - ["Local Files"](#local-files) uses native libraries to read and write files on | ||||
| the device. | ||||
| 
 | ||||
| The "Complete Example" creates an app that looks like the screenshots below: | ||||
| 
 | ||||
| @ -30,17 +45,9 @@ The "Complete Example" creates an app that looks like the screenshots below: | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| ["Fetching Remote Data"](#fetching-remote-data) uses the built-in `fetch` to | ||||
| download and parse remote workbook files. | ||||
| :::caution pass | ||||
| 
 | ||||
| ["Native Libraries"](#native-libraries) uses native libraries to read and write | ||||
| files in the local device. | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| **Before reading this demo, follow the official React Native CLI Guide!** | ||||
| 
 | ||||
| Development Environment Guide: <https://reactnative.dev/docs/environment-setup> | ||||
| **Before testing this demo, follow the official React Native CLI Guide!**[^1] | ||||
| 
 | ||||
| Follow the instructions for iOS (requires macOS) and for Android. They will | ||||
| cover installation and system configuration. You should be able to build and run | ||||
| @ -48,42 +55,178 @@ a sample app in the Android and the iOS (if applicable) simulators. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be | ||||
| imported from the main `App.js` entrypoint or any script in the project. | ||||
| 
 | ||||
| ### Internal State | ||||
| 
 | ||||
| For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state. | ||||
| 
 | ||||
| <table><thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead><tbody><tr><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td><td> | ||||
| 
 | ||||
| ```js | ||||
| [ | ||||
|   ["Name", "Index"], | ||||
|   ["Bill Clinton", 42], | ||||
|   ["GeorgeW Bush", 43], | ||||
|   ["Barack Obama", 44], | ||||
|   ["Donald Trump", 45], | ||||
|   ["Joseph Biden", 46] | ||||
| ] | ||||
| ``` | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| Each array within the structure corresponds to one row. | ||||
| 
 | ||||
| This demo also keeps track of the column widths as a single array of numbers. | ||||
| The widths are used by the display component. | ||||
| 
 | ||||
| _Complete State_ | ||||
| 
 | ||||
| The complete state is initialized with the following snippet: | ||||
| 
 | ||||
| ```js | ||||
| const [data, setData] = useState([ | ||||
|   "SheetJS".split(""), | ||||
|   [5,4,3,3,7,9,5], | ||||
|   [8,6,7,5,3,0,9] | ||||
| ]); | ||||
| const [widths, setWidths] = useState(Array.from({length:7}, () => 20)); | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| #### Updating State | ||||
| 
 | ||||
| Starting from a SheetJS worksheet object, `sheet_to_json`[^3] with the `header` | ||||
| option can generate an array of arrays: | ||||
| 
 | ||||
| ```js | ||||
| /* assuming `wb` is a SheetJS workbook */ | ||||
| function update_state(wb) { | ||||
|   /* convert first worksheet to AOA */ | ||||
|   const wsname = wb.SheetNames[0]; | ||||
|   const ws = wb.Sheets[wsname]; | ||||
|   const data = utils.sheet_to_json(ws, {header:1}); | ||||
| 
 | ||||
|   /* update state */ | ||||
|   setData(data); | ||||
| 
 | ||||
|   /* update column widths */ | ||||
|   setWidths(make_width(data)); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| _Calculating Column Widths_ | ||||
| 
 | ||||
| Column widths can be calculated by walking each column and calculating the max | ||||
| data width. Using the array of arrays: | ||||
| 
 | ||||
| ```js | ||||
| /* this function takes an array of arrays and generates widths */ | ||||
| function make_width(aoa) { | ||||
|   /* walk each row */ | ||||
|   aoa.forEach((r) => { | ||||
|     /* walk each column */ | ||||
|     r.forEach((c, C) => { | ||||
|       /* update column width based on the length of the cell contents */ | ||||
|       res[C] = Math.max(res[C]||60, String(c).length * 10); | ||||
|     }); | ||||
|   }); | ||||
|   /* use a default value for columns with no data */ | ||||
|   for(let C = 0; C < res.length; ++C) if(!res[C]) res[C] = 60; | ||||
|   return res; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| #### Exporting State | ||||
| 
 | ||||
| `aoa_to_sheet`[^4] builds a SheetJS worksheet object from the array of arrays: | ||||
| 
 | ||||
| ```js | ||||
| /* generate a SheetJS workbook from the state */ | ||||
| function export_state() { | ||||
|   /* convert AOA back to worksheet */ | ||||
|   const ws = utils.aoa_to_sheet(data); | ||||
| 
 | ||||
|   /* build new workbook */ | ||||
|   const wb = utils.book_new(); | ||||
|   utils.book_append_sheet(wb, ws, "SheetJS"); | ||||
| 
 | ||||
|   return wb; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Displaying Data | ||||
| 
 | ||||
| The demos uses `react-native-table-component` to display the first worksheet. | ||||
| 
 | ||||
| The demos use components similar to the example below: | ||||
| 
 | ||||
| ```jsx | ||||
| import { ScrollView } from 'react-native'; | ||||
| import { Table, Row, Rows, TableWrapper } from 'react-native-table-component'; | ||||
| 
 | ||||
| ( | ||||
|   {/* Horizontal scroll */} | ||||
|   <ScrollView horizontal={true} > | ||||
|     {/* Table container */} | ||||
|     <Table> | ||||
|       {/* Frozen Header Row */} | ||||
|       <TableWrapper> | ||||
|         {/* First row */} | ||||
|         <Row data={data[0]} widthArr={widths}/> | ||||
|       </TableWrapper> | ||||
|       {/* Scrollable Data Rows */} | ||||
|       <ScrollView> | ||||
|         <TableWrapper> | ||||
|           {/* Remaining Rows */} | ||||
|           <Rows data={data.slice(1)} widthArr={widths}/> | ||||
|         </TableWrapper> | ||||
|       </ScrollView> | ||||
|     </Table> | ||||
|   </ScrollView> | ||||
| ) | ||||
| ``` | ||||
| 
 | ||||
| `data.slice(1)` in the `Rows` component returns data starting from the second | ||||
| row. This neatly skips the first header row. | ||||
| 
 | ||||
| ## Fetching Remote Data | ||||
| 
 | ||||
| :::info | ||||
| React Native versions starting from `0.72.0`[^5] support binary data with `fetch`. | ||||
| 
 | ||||
| React Native `0.72.0` will support binary data with `fetch`. For older versions, | ||||
| [a native library](#native-libraries) can provide support. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 
 | ||||
| React Native 0.72.0 will support binary data with `fetch`: | ||||
| This snippet downloads and parses <https://sheetjs.com/pres.xlsx>: | ||||
| 
 | ||||
| ```js | ||||
| /* fetch data into an ArrayBuffer */ | ||||
| const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); | ||||
| const ab = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | ||||
| /* parse data */ | ||||
| const wb = XLSX.read(ab); | ||||
| ``` | ||||
| 
 | ||||
| ### Fetch Demo | ||||
| 
 | ||||
| The following demo uses `react-native-table-component` to display the first | ||||
| worksheet in a simple table. | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on an Intel Mac on 2023 April 24 with RN `0.72.0-rc.1`. | ||||
| This demo was tested on an Intel Mac on 2023 July 02 with RN `0.72.1`. | ||||
| 
 | ||||
| The iOS simulator runs iOS 16.2 on an iPhone SE (3rd generation). | ||||
| 
 | ||||
| The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 1) Create project: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native init SheetJSRNFetch --version="0.72.0-rc.1" | ||||
| npx -y react-native@0.72.1 init SheetJSRNFetch --version="0.72.1" | ||||
| ``` | ||||
| 
 | ||||
| 2) Install shared dependencies: | ||||
| @ -95,69 +238,46 @@ npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | ||||
| npm i -S react-native-table-component@1.2.0 @types/react-native-table-component`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| Refresh iOS project by running `pod install` from the `ios` subfolder: | ||||
| 
 | ||||
| ```bash | ||||
| cd ios; pod install; cd .. | ||||
| ``` | ||||
| 
 | ||||
| 3) Download [`App.tsx`](pathname:///reactnative/App.tsx) and replace: | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/reactnative/App.tsx | ||||
| ``` | ||||
| 
 | ||||
| **iOS Testing** | ||||
| 
 | ||||
| Start the iOS emulator: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native run-ios | ||||
| ``` | ||||
| 
 | ||||
| When opened, the app should look like the "Before" screenshot below.  After | ||||
| tapping "Import data from a spreadsheet", the app should show new data: | ||||
| 
 | ||||
| <table><thead><tr> | ||||
|   <th>Before</th> | ||||
|   <th>After</th> | ||||
| </tr></thead><tbody><tr><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| **Android Testing** | ||||
| 
 | ||||
| Start the Android emulator: | ||||
| 4) Install or switch to Java 11[^6] | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| When the demo was last tested on macOS, `java -version` displayed the following: | ||||
| 
 | ||||
| ``` | ||||
| openjdk version "11.0.19" 2023-04-18 LTS | ||||
| OpenJDK Runtime Environment Zulu11.64+19-CA (build 11.0.19+7-LTS) | ||||
| OpenJDK 64-Bit Server VM Zulu11.64+19-CA (build 11.0.19+7-LTS, mixed mode) | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 5) Start the Android emulator: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native run-android | ||||
| ``` | ||||
| 
 | ||||
| :::note | ||||
| :::caution pass | ||||
| 
 | ||||
| When this demo was last tested, the simulator failed with the message | ||||
| If the initial launch fails with an error referencing the emulator, manually | ||||
| start the emulator and try again. | ||||
| 
 | ||||
| > Unable to load script.  Make sure you're either Running Metro ... | ||||
| 
 | ||||
| The workaround is to launch Metro directly: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native start | ||||
| ``` | ||||
| 
 | ||||
| Press `a` in the terminal window and Metro will try to reload the app. | ||||
| Gradle errors typically stem from a Java version mismatch. Run `java -version` | ||||
| and verify that the Java major version is 11. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 
 | ||||
| When opened, the app should look like the "Before" screenshot below.  After | ||||
| tapping "Import data from a spreadsheet", the app should show new data: | ||||
| 6) When opened, the app should look like the "Before" screenshot below. After | ||||
| tapping "Import data from a spreadsheet", verify that the app shows new data: | ||||
| 
 | ||||
| <table><thead><tr> | ||||
|   <th>Before</th> | ||||
| @ -172,10 +292,45 @@ tapping "Import data from a spreadsheet", the app should show new data: | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| **iOS Testing** | ||||
| 
 | ||||
| ## Native Libraries | ||||
| :::warning pass | ||||
| 
 | ||||
| :::warning | ||||
| iOS testing requires macOS. It does not work on Windows. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 7) Refresh iOS project by running `pod install` from the `ios` subfolder: | ||||
| 
 | ||||
| ```bash | ||||
| cd ios; pod install; cd .. | ||||
| ``` | ||||
| 
 | ||||
| 8) Start the iOS emulator: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native run-ios | ||||
| ``` | ||||
| 
 | ||||
| 9) When opened, the app should look like the "Before" screenshot below.  After | ||||
| tapping "Import data from a spreadsheet", verify that the app shows new data: | ||||
| 
 | ||||
| <table><thead><tr> | ||||
|   <th>Before</th> | ||||
|   <th>After</th> | ||||
| </tr></thead><tbody><tr><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| ## Local Files | ||||
| 
 | ||||
| :::warning pass | ||||
| 
 | ||||
| React Native does not provide a native file picker or a method for reading and | ||||
| writing data from documents on the devices. A third-party library must be used. | ||||
| @ -187,40 +342,41 @@ consulted before picking a library. | ||||
| ::: | ||||
| 
 | ||||
| The following table lists tested file plugins.  "OS" lists tested platforms | ||||
| ("A" for Android and "I" for iOS).  "Copy" indicates whether an explicit copy | ||||
| is needed (file picker copies to cache directory and file plugin reads cache). | ||||
| ("A" for Android and "I" for iOS). | ||||
| 
 | ||||
| | File system Plugin         | File Picker Plugin             |  OS  | Copy | | ||||
| |:---------------------------|:-------------------------------|:----:|:-----| | ||||
| | `react-native-file-access` | `react-native-document-picker` | `AI` |      | | ||||
| | `react-native-blob-util`   | `react-native-document-picker` | `AI` | YES  | | ||||
| | `rn-fetch-blob`            | `react-native-document-picker` | `AI` | YES  | | ||||
| | `react-native-fs`          | `react-native-document-picker` | `AI` | YES  | | ||||
| | `expo-file-system`         | `expo-document-picker`         | ` I` | YES  | | ||||
| | File system Plugin         | File Picker Plugin             |  OS  | | ||||
| |:---------------------------|:-------------------------------|:----:| | ||||
| | `react-native-file-access` | `react-native-document-picker` | `AI` | | ||||
| | `react-native-blob-util`   | `react-native-document-picker` | `AI` | | ||||
| | `rn-fetch-blob`            | `react-native-document-picker` | `AI` | | ||||
| | `react-native-fs`          | `react-native-document-picker` | `AI` | | ||||
| | `expo-file-system`         | `expo-document-picker`         | ` I` | | ||||
| 
 | ||||
| ### RN File Picker | ||||
| 
 | ||||
| The "File Picker" library handles two platform-specific steps: | ||||
| 
 | ||||
| 1) Show a view that allows users to select a file from their device | ||||
| 
 | ||||
| 2) Copy the selected file to a location that can be read by the application | ||||
| 
 | ||||
| The following libraries have been tested: | ||||
| 
 | ||||
| #### `react-native-document-picker` | ||||
| 
 | ||||
| <details open><summary><b>Selecting a file</b> (click to show)</summary> | ||||
| 
 | ||||
| When a copy is not needed: | ||||
| The setting `copyTo: "cachesDirectory"` must be set: | ||||
| 
 | ||||
| ```js | ||||
| import { pickSingle } from 'react-native-document-picker'; | ||||
| 
 | ||||
| const f = await pickSingle({allowMultiSelection: false, mode: "open" }); | ||||
| const path = f.uri; // this path can be read by RN file plugins | ||||
| ``` | ||||
| 
 | ||||
| When a copy is needed: | ||||
| 
 | ||||
| ```js | ||||
| import { pickSingle } from 'react-native-document-picker'; | ||||
| 
 | ||||
| const f = await pickSingle({allowMultiSelection: false, copyTo: "cachesDirectory", mode: "open" }); | ||||
| const f = await pickSingle({ | ||||
|   allowMultiSelection: false, | ||||
|   // highlight-next-line | ||||
|   copyTo: "cachesDirectory", | ||||
|   mode: "open" | ||||
| }); | ||||
| const path = f.fileCopyUri; // this path can be read by RN file plugins | ||||
| ``` | ||||
| 
 | ||||
| @ -240,7 +396,7 @@ const result = await DocumentPicker.getDocumentAsync({ | ||||
|   copyToCacheDirectory: true, | ||||
|   type: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] | ||||
| }); | ||||
| const path = result.uri; | ||||
| const path = result.uri; // this path can be read by RN file plugins | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| @ -433,11 +589,11 @@ await FileSystem.writeAsStringAsync(FileSystem.documentDirectory + "sheetjs.xlsx | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ## Demo | ||||
| ### Demo | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on an Intel Mac on 2023 April 30 with RN `0.72.0-rc.1`. | ||||
| This demo was tested on an Intel Mac on 2023 July 02 with RN `0.72.1`. | ||||
| 
 | ||||
| The iOS simulator runs iOS 16.2 on an iPhone 14. | ||||
| 
 | ||||
| @ -449,8 +605,8 @@ The Android simulator runs Android 12 (S) Platform 31 on a Pixel 5. | ||||
| 
 | ||||
| There are many moving parts and pitfalls with React Native apps. It is strongly | ||||
| recommended to follow the official React Native tutorials for iOS and Android | ||||
| before approaching this demo.  Details like creating an Android Virtual Device | ||||
| are not covered here. | ||||
| before approaching this demo.[^7] Details including Android Virtual Device | ||||
| configuration are not covered here. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -459,7 +615,7 @@ This example tries to separate the library-specific functions. | ||||
| 1) Create project: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native init SheetJSRN --version="0.72.0-rc.1" | ||||
| npx react-native init SheetJSRN --version="0.72.1" | ||||
| ``` | ||||
| 
 | ||||
| 2) Install shared dependencies: | ||||
| @ -519,7 +675,6 @@ import { Platform } from 'react-native'; | ||||
| import RNFetchBlob from 'react-native-blob-util'; | ||||
| 
 | ||||
| async function pickAndParse() { | ||||
|   /* rn-fetch-blob / react-native-blob-util need a copy */ | ||||
|   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | ||||
|   let path = f.fileCopyUri; | ||||
|   if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, RNFetchBlob.fs.dirs.DocumentDir + "/"); | ||||
| @ -560,11 +715,6 @@ import { Platform } from 'react-native'; | ||||
| import { Dirs, FileSystem } from 'react-native-file-access'; | ||||
| 
 | ||||
| async function pickAndParse() { | ||||
|   /* react-native-file-access in RN < 0.72 does not need a copy */ | ||||
|   //const f = await pickSingle({allowMultiSelection: false, mode: "open" }); | ||||
|   //const res = await FileSystem.readFile(f.uri, "base64"); | ||||
|   //return read(res, {type: 'base64'}); | ||||
|   /* react-native-file-access in RN >= 0.72 needs a copy */ | ||||
|   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | ||||
|   let path = f.fileCopyUri; | ||||
|   const res = await (await fetch(path)).arrayBuffer(); | ||||
| @ -603,7 +753,6 @@ import { Platform } from 'react-native'; | ||||
| import RNFetchBlob from 'rn-fetch-blob'; | ||||
| 
 | ||||
| async function pickAndParse() { | ||||
|   /* rn-fetch-blob / react-native-blob-util need a copy */ | ||||
|   const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" }); | ||||
|   let path = f.fileCopyUri; | ||||
|   if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, RNFetchBlob.fs.dirs.DocumentDir + "/"); | ||||
| @ -643,7 +792,6 @@ import { pickSingle } from 'react-native-document-picker'; | ||||
| import { writeFile, readFile, DocumentDirectoryPath } from 'react-native-fs'; | ||||
| 
 | ||||
| async function pickAndParse() { | ||||
|   /* react-native-fs needs a copy */ | ||||
|   const f = await pickSingle({allowMultiSelection: false, copyTo: "cachesDirectory", mode: "open" }); | ||||
|   const bstr = await readFile(f.fileCopyUri, 'ascii'); | ||||
|   return read(bstr, {type:'binary'}); | ||||
| @ -665,12 +813,7 @@ const make_width = ws => { | ||||
| 
 | ||||
| :::warning | ||||
| 
 | ||||
| At the time of testing, Expo did not support RN 0.72 .  The project should be | ||||
| created with React Native 0.67.2: | ||||
| 
 | ||||
| ```bash | ||||
| npx react-native init SheetJSRN --version="0.67.2" | ||||
| ``` | ||||
| At the time of testing, Expo Modules were incompatible with Android projects. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -793,3 +936,11 @@ Once selected, the screen should refresh with new contents: | ||||
| adb exec-out run-as com.sheetjsrn cat files/sheetjsw.xlsx > /tmp/sheetjsw.xlsx | ||||
| npx xlsx-cli /tmp/sheetjsw.xlsx | ||||
| ``` | ||||
| 
 | ||||
| [^1]: Follow the ["React Native CLI Quickstart"](https://reactnative.dev/docs/environment-setup) and select the appropriate "Development OS". | ||||
| [^2]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays) | ||||
| [^3]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output) | ||||
| [^4]: See ["Array of Arrays Input" in "Utility Functions"](/docs/api/utilities/array#array-of-arrays-input) | ||||
| [^5]: React-Native commit [`5b597b5`](https://github.com/facebook/react-native/commit/5b597b5ff94953accc635ed3090186baeecb3873) added the final piece required for `fetch` support. It landed in version `0.72.0-rc.1` and is available in official releases starting from `0.72.0`. | ||||
| [^6]: When the demo was last tested, the Zulu11 distribution of Java 11 was installed through the macOS Brew package manager. [Direct downloads are available at `azul.com`](https://www.azul.com/downloads/?version=java-11-lts&package=jdk#zulu) | ||||
| [^7]: Follow the ["React Native CLI Quickstart"](https://reactnative.dev/docs/environment-setup) for Android (and iOS, if applicable) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user