2023-01-05 23:33:49 +00:00
---
title: React Native
2023-07-02 06:45:10 +00:00
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.
2023-02-28 11:40:44 +00:00
pagination_prev: demos/static/index
2023-01-05 23:33:49 +00:00
pagination_next: demos/desktop/index
sidebar_position: 1
sidebar_custom_props:
summary: React + Native Rendering
---
2023-07-02 06:45:10 +00:00
# Sheets on the Go with React Native
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-01-05 23:33:49 +00:00
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
2023-05-01 01:27:02 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
[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.
2023-01-05 23:33:49 +00:00
The "Complete Example" creates an app that looks like the screenshots below:
< table > < thead > < tr >
< th > < a href = "#demo" > iOS< / a > < / th >
< th > < a href = "#demo" > Android< / a > < / th >
< / tr > < / thead > < tbody > < tr > < td >
![iOS screenshot ](pathname:///mobile/rnios3.png )
< / td > < td >
![Android screenshot ](pathname:///mobile/rnand3.png )
< / td > < / tr > < / tbody > < / table >
2023-07-02 06:45:10 +00:00
:::caution pass
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
**Before testing this demo, follow the official React Native CLI Guide!**[^1]
2023-04-24 08:50:42 +00:00
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
a sample app in the Android and the iOS (if applicable) simulators.
:::
2023-07-02 06:45:10 +00:00
## Integration Details
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
The [SheetJS NodeJS Module ](/docs/getting-started/installation/nodejs ) can be
imported from the main `App.js` entrypoint or any script in the project.
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
### Internal State
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state.
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
< table > < thead > < tr > < th > Spreadsheet< / th > < th > Array of Arrays< / th > < / tr > < / thead > < tbody > < tr > < td >
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
![`pres.xlsx` data ](pathname:///pres.png )
< / 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
React Native versions starting from `0.72.0` [^5] support binary data with `fetch` .
This snippet downloads and parses < https: / / sheetjs . com / pres . xlsx > :
2023-04-24 08:50:42 +00:00
```js
/* fetch data into an ArrayBuffer */
2023-07-02 06:45:10 +00:00
const ab = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
2023-04-24 08:50:42 +00:00
/* parse data */
const wb = XLSX.read(ab);
```
### Fetch Demo
:::note
2023-07-02 06:45:10 +00:00
This demo was tested on an Intel Mac on 2023 July 02 with RN `0.72.1` .
2023-04-24 08:50:42 +00:00
The iOS simulator runs iOS 16.2 on an iPhone SE (3rd generation).
2023-07-02 06:45:10 +00:00
The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3.
2023-04-24 08:50:42 +00:00
:::
1) Create project:
```bash
2023-07-02 06:45:10 +00:00
npx -y react-native@0.72.1 init SheetJSRNFetch --version="0.72.1"
2023-04-24 08:50:42 +00:00
```
2) Install shared dependencies:
2023-05-01 01:27:02 +00:00
< CodeBlock language = "bash" > {`\
2023-04-24 08:50:42 +00:00
cd SheetJSRNFetch
2023-06-05 20:12:53 +00:00
curl -LO https://docs.sheetjs.com/logo.png
2023-05-01 01:27:02 +00:00
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 >
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
3) Download [`App.tsx` ](pathname:///reactnative/App.tsx ) and replace:
2023-04-24 08:50:42 +00:00
```bash
2023-07-02 06:45:10 +00:00
curl -LO https://docs.sheetjs.com/reactnative/App.tsx
2023-04-24 08:50:42 +00:00
```
2023-07-02 06:45:10 +00:00
**Android Testing**
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
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)
2023-04-24 08:50:42 +00:00
```
2023-07-02 06:45:10 +00:00
:::
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
5) Start the Android emulator:
2023-04-24 08:50:42 +00:00
```bash
2023-07-02 06:45:10 +00:00
npx react-native run-android
2023-04-24 08:50:42 +00:00
```
2023-07-02 06:45:10 +00:00
:::caution pass
If the initial launch fails with an error referencing the emulator, manually
start the emulator and try again.
Gradle errors typically stem from a Java version mismatch. Run `java -version`
and verify that the Java major version is 11.
:::
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:
2023-04-24 08:50:42 +00:00
< table > < thead > < tr >
< th > Before< / th >
< th > After< / th >
< / tr > < / thead > < tbody > < tr > < td >
2023-07-02 06:45:10 +00:00
![before screenshot ](pathname:///reactnative/andfetch1.png )
2023-04-24 08:50:42 +00:00
< / td > < td >
2023-07-02 06:45:10 +00:00
![after screenshot ](pathname:///reactnative/andfetch2.png )
2023-04-24 08:50:42 +00:00
< / td > < / tr > < / tbody > < / table >
2023-07-02 06:45:10 +00:00
**iOS Testing**
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
:::warning pass
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
iOS testing requires macOS. It does not work on Windows.
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
:::
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
7) Refresh iOS project by running `pod install` from the `ios` subfolder:
2023-04-24 08:50:42 +00:00
```bash
2023-07-02 06:45:10 +00:00
cd ios; pod install; cd ..
2023-04-24 08:50:42 +00:00
```
2023-07-02 06:45:10 +00:00
8) Start the iOS emulator:
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
```bash
npx react-native run-ios
```
2023-04-24 08:50:42 +00:00
2023-07-02 06:45:10 +00:00
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:
2023-04-24 08:50:42 +00:00
< table > < thead > < tr >
< th > Before< / th >
< th > After< / th >
< / tr > < / thead > < tbody > < tr > < td >
2023-07-02 06:45:10 +00:00
![before screenshot ](pathname:///reactnative/iosfetch1.png )
2023-04-24 08:50:42 +00:00
< / td > < td >
2023-07-02 06:45:10 +00:00
![after screenshot ](pathname:///reactnative/iosfetch2.png )
2023-04-24 08:50:42 +00:00
< / td > < / tr > < / tbody > < / table >
2023-07-02 06:45:10 +00:00
## Local Files
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
:::warning pass
2023-01-05 23:33:49 +00:00
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.
Since React Native internals change between releases, libraries may only work
with specific versions of React Native. Project documentation should be
consulted before picking a library.
:::
The following table lists tested file plugins. "OS" lists tested platforms
2023-07-02 06:45:10 +00:00
("A" for Android and "I" for iOS).
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
| 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` |
2023-01-05 23:33:49 +00:00
### RN File Picker
2023-07-02 06:45:10 +00:00
The "File Picker" library handles two platform-specific steps:
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
1) Show a view that allows users to select a file from their device
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
2) Copy the selected file to a location that can be read by the application
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
The following libraries have been tested:
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
#### `react-native-document-picker`
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
< details open > < summary > < b > Selecting a file< / b > (click to show)< / summary >
2023-01-05 23:33:49 +00:00
2023-07-02 06:45:10 +00:00
The setting `copyTo: "cachesDirectory"` must be set:
2023-01-05 23:33:49 +00:00
```js
import { pickSingle } from 'react-native-document-picker';
2023-07-02 06:45:10 +00:00
const f = await pickSingle({
allowMultiSelection: false,
// highlight-next-line
copyTo: "cachesDirectory",
mode: "open"
});
2023-01-05 23:33:49 +00:00
const path = f.fileCopyUri; // this path can be read by RN file plugins
```
< / details >
#### `expo-document-picker`
< details > < summary > < b > Selecting a file< / b > (click to show)< / summary >
When using `DocumentPicker.getDocumentAsync` , enable `copyToCacheDirectory` :
```js
import * as DocumentPicker from 'expo-document-picker';
const result = await DocumentPicker.getDocumentAsync({
// highlight-next-line
copyToCacheDirectory: true,
type: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
});
2023-07-02 06:45:10 +00:00
const path = result.uri; // this path can be read by RN file plugins
2023-01-05 23:33:49 +00:00
```
< / details >
### RN File Plugins
The following libraries have been tested:
#### `react-native-blob-util` and `rn-fetch-blob`
:::note Historical Context
The `react-native-fetch-blob` project was archived in 2019. At the time, there
were a number of project forks. The maintainers blessed the `rn-fetch-blob`
fork as the spiritual successor.
`react-native-blob-util` is an active fork of `rn-fetch-blob`
2023-05-01 01:27:02 +00:00
When this demo was last tested, `rn-fetch-blob` and `react-native-blob-util`
both worked with the tested iOS and Android SDK versions. The APIs are identical
for the purposes of working with files.
2023-01-05 23:33:49 +00:00
:::
The `ascii` type returns an array of numbers corresponding to the raw bytes.
A `Uint8Array` from the data is compatible with the `buffer` type.
< details open > < summary > < b > Reading and Writing snippets< / b > (click to show)< / summary >
The snippets use `rn-fetch-blob` . To use `react-native-blob-util` , change the
`import` statements to load the module.
_Reading Data_
```js
import * as XLSX from "xlsx";
import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util
const { readFile } = RNFetchBlob.fs;
const res = await readFile(path, 'ascii');
const wb = XLSX.read(new Uint8Array(res), {type:'buffer'});
```
:::caution
On iOS, the URI from `react-native-document-picker` must be massaged:
```js
import { pickSingle } from 'react-native-document-picker';
import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util
const { readFile, dirs: { DocumentDir } } = RNFetchBlob.fs;
const f = await pickSingle({
// highlight-start
// Instruct the document picker to copy file to Documents directory
copyTo: "documentDirectory",
// highlight-end
allowMultiSelection: false, mode: "open" });
// highlight-start
// `f.uri` is the original path and `f.fileCopyUri` is the path to the copy
let path = f.fileCopyUri;
// iOS workaround
if (Platform.OS === 'ios') path = path.replace(/^.*\/Documents\//, DDP + "/");
// highlight-end
const res = await readFile(path, 'ascii');
```
:::
_Writing Data_
```js
import * as XLSX from "xlsx";
import RNFetchBlob from 'rn-fetch-blob'; // or react-native-blob-util
const { writeFile, readFile, dirs:{ DocumentDir } } = RNFetchBlob.fs;
const wbout = XLSX.write(wb, {type:'buffer', bookType:"xlsx"});
const file = DocumentDir + "/sheetjsw.xlsx";
const res = await writeFile(file, Array.from(wbout), 'ascii');
```
< / details >
#### `react-native-file-access`
The `base64` encoding returns strings compatible with the `base64` type:
< details open > < summary > < b > Reading and Writing snippets< / b > (click to show)< / summary >
_Reading Data_
```js
import * as XLSX from "xlsx";
import { FileSystem } from "react-native-file-access";
const b64 = await FileSystem.readFile(path, "base64");
/* b64 is a Base64 string */
const workbook = XLSX.read(b64, {type: "base64"});
```
_Writing Data_
```js
import * as XLSX from "xlsx";
import { Dirs, FileSystem } from "react-native-file-access";
const DDP = Dirs.DocumentDir + "/";
const b64 = XLSX.write(workbook, {type:'base64', bookType:"xlsx"});
/* b64 is a Base64 string */
await FileSystem.writeFile(DDP + "sheetjs.xlsx", b64, "base64");
```
< / details >
#### `react-native-fs`
The `ascii` encoding returns binary strings compatible with the `binary` type:
< details open > < summary > < b > Reading and Writing snippets< / b > (click to show)< / summary >
_Reading Data_
```js
import * as XLSX from "xlsx";
import { readFile } from "react-native-fs";
const bstr = await readFile(path, "ascii");
/* bstr is a binary string */
const workbook = XLSX.read(bstr, {type: "binary"});
```
_Writing Data_
```js
import * as XLSX from "xlsx";
import { writeFile, DocumentDirectoryPath } from "react-native-fs";
const bstr = XLSX.write(workbook, {type:'binary', bookType:"xlsx"});
/* bstr is a binary string */
await writeFile(DocumentDirectoryPath + "/sheetjs.xlsx", bstr, "ascii");
```
< / details >
#### `expo-file-system`
:::caution
Some Expo APIs return URI that cannot be read with `expo-file-system` . This
will manifest as an error:
> Unsupported scheme for location '...'
The [`expo-document-picker` ](#expo-document-picker ) snippet makes a local copy.
:::
The `EncodingType.Base64` encoding is compatible with `base64` type.
< details > < summary > < b > Reading and Writing snippets< / b > (click to show)< / summary >
_Reading Data_
Calling `FileSystem.readAsStringAsync` with `FileSystem.EncodingType.Base64`
encoding returns a promise resolving to a string compatible with `base64` type:
```js
import * as XLSX from "xlsx";
import * as FileSystem from 'expo-file-system';
const b64 = await FileSystem.readAsStringAsync(uri, { encoding: FileSystem.EncodingType.Base64 });
const workbook = XLSX.read(b64, { type: "base64" });
```
_Writing Data_
The `FileSystem.EncodingType.Base64` encoding accepts Base64 strings:
```js
import * as XLSX from "xlsx";
import * as FileSystem from 'expo-file-system';
const b64 = XLSX.write(workbook, {type:'base64', bookType:"xlsx"});
/* b64 is a Base64 string */
await FileSystem.writeAsStringAsync(FileSystem.documentDirectory + "sheetjs.xlsx", b64, { encoding: FileSystem.EncodingType.Base64 });
```
< / details >
2023-07-02 06:45:10 +00:00
### Demo
2023-01-05 23:33:49 +00:00
:::note
2023-07-02 06:45:10 +00:00
This demo was tested on an Intel Mac on 2023 July 02 with RN `0.72.1` .
2023-01-05 23:33:49 +00:00
2023-05-01 01:27:02 +00:00
The iOS simulator runs iOS 16.2 on an iPhone 14.
2023-01-05 23:33:49 +00:00
The Android simulator runs Android 12 (S) Platform 31 on a Pixel 5.
:::
:::warning
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
2023-07-02 06:45:10 +00:00
before approaching this demo.[^7] Details including Android Virtual Device
configuration are not covered here.
2023-01-05 23:33:49 +00:00
:::
This example tries to separate the library-specific functions.
1) Create project:
2023-04-24 08:50:42 +00:00
```bash
2023-07-02 06:45:10 +00:00
npx react-native init SheetJSRN --version="0.72.1"
2023-01-05 23:33:49 +00:00
```
2) Install shared dependencies:
2023-05-01 01:27:02 +00:00
< CodeBlock language = "bash" > {`\
2023-01-05 23:33:49 +00:00
cd SheetJSRN
2023-06-05 20:12:53 +00:00
curl -LO https://docs.sheetjs.com/logo.png
2023-05-01 01:27:02 +00:00
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
npm i -S react-native-table-component@1.2.0 react-native-document-picker@8.2.0`}
< / CodeBlock >
2023-01-05 23:33:49 +00:00
Refresh iOS project by running `pod install` from the `ios` subfolder:
```bash
cd ios
pod install
cd ..
```
3) Download [`index.js` ](pathname:///mobile/index.js ) and replace:
```bash
curl -LO https://docs.sheetjs.com/mobile/index.js
```
Start the iOS emulator:
```bash
npx react-native run-ios
```
You should see the skeleton app:
![React Native iOS App ](pathname:///mobile/rnios1.png )
4) Pick a filesystem library for integration:
< Tabs >
< TabItem value = "RNBU" label = "RNBU" >
Install `react-native-blob-util` dependency:
```bash
2023-05-01 01:27:02 +00:00
npm i -S react-native-blob-util@0.17.1
2023-01-05 23:33:49 +00:00
```
Add the highlighted lines to `index.js` :
```js title="index.js"
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
// highlight-start
import { read, write } from 'xlsx';
import { pickSingle } from 'react-native-document-picker';
import { Platform } from 'react-native';
import RNFetchBlob from 'react-native-blob-util';
async function pickAndParse() {
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 + "/");
2023-05-01 01:27:02 +00:00
const res = await (await fetch(path)).arrayBuffer(); // RN >= 0.72
// const res = await RNFetchBlob.fs.readFile(path, 'ascii'); // RN < 0.72
2023-01-05 23:33:49 +00:00
return read(new Uint8Array(res), {type: 'buffer'});
}
async function writeWorkbook(wb) {
const wbout = write(wb, {type:'buffer', bookType:"xlsx"});
const file = RNFetchBlob.fs.dirs.DocumentDir + "/sheetjsw.xlsx";
await RNFetchBlob.fs.writeFile(file, Array.from(wbout), 'ascii');
return file;
}
// highlight-end
const make_width = ws => {
```
< / TabItem >
< TabItem value = "RNFA" label = "RNFA" >
Install `react-native-file-access` dependency:
```bash
2023-05-01 01:27:02 +00:00
npm i -S react-native-file-access@2.6.0
2023-01-05 23:33:49 +00:00
```
Add the highlighted lines to `index.js` :
```js title="index.js"
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
// highlight-start
import { read, write } from 'xlsx';
import { pickSingle } from 'react-native-document-picker';
2023-05-01 01:27:02 +00:00
import { Platform } from 'react-native';
2023-01-05 23:33:49 +00:00
import { Dirs, FileSystem } from 'react-native-file-access';
async function pickAndParse() {
2023-05-01 01:27:02 +00:00
const f = await pickSingle({allowMultiSelection: false, copyTo: "documentDirectory", mode: "open" });
let path = f.fileCopyUri;
const res = await (await fetch(path)).arrayBuffer();
return read(new Uint8Array(res), {type: 'buffer'});
2023-01-05 23:33:49 +00:00
}
async function writeWorkbook(wb) {
const wbout = write(wb, {type:'base64', bookType:"xlsx"});
const file = Dirs.DocumentDir + "/sheetjsw.xlsx";
await FileSystem.writeFile(file, wbout, "base64");
return file;
}
// highlight-end
const make_width = ws => {
```
< / TabItem >
< TabItem value = "RNFB" label = "RNFB" >
Install `rn-fetch-blob` dependency:
```bash
2023-05-01 01:27:02 +00:00
npm i -S rn-fetch-blob@0.12.0
2023-01-05 23:33:49 +00:00
```
Add the highlighted lines to `index.js` :
```js title="index.js"
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
// highlight-start
import { read, write } from 'xlsx';
import { pickSingle } from 'react-native-document-picker';
import { Platform } from 'react-native';
import RNFetchBlob from 'rn-fetch-blob';
async function pickAndParse() {
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 + "/");
2023-05-01 01:27:02 +00:00
const res = await (await fetch(path)).arrayBuffer(); // RN >= 0.72
// const res = await RNFetchBlob.fs.readFile(path, 'ascii'); // RN < 0.72
2023-01-05 23:33:49 +00:00
return read(new Uint8Array(res), {type: 'buffer'});
}
async function writeWorkbook(wb) {
const wbout = write(wb, {type:'buffer', bookType:"xlsx"});
const file = RNFetchBlob.fs.dirs.DocumentDir + "/sheetjsw.xlsx";
await RNFetchBlob.fs.writeFile(file, Array.from(wbout), 'ascii');
return file;
}
// highlight-end
const make_width = ws => {
```
< / TabItem >
< TabItem value = "RNFS" label = "RNFS" >
Install `react-native-fs` dependency:
```bash
2023-05-01 01:27:02 +00:00
npm i -S react-native-fs@2.20.0
2023-01-05 23:33:49 +00:00
```
Add the highlighted lines to `index.js` :
```js title="index.js"
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
// highlight-start
import { read, write } from 'xlsx';
import { pickSingle } from 'react-native-document-picker';
import { writeFile, readFile, DocumentDirectoryPath } from 'react-native-fs';
async function pickAndParse() {
const f = await pickSingle({allowMultiSelection: false, copyTo: "cachesDirectory", mode: "open" });
const bstr = await readFile(f.fileCopyUri, 'ascii');
return read(bstr, {type:'binary'});
}
async function writeWorkbook(wb) {
const wbout = write(wb, {type:'binary', bookType:"xlsx"});
const file = DocumentDirectoryPath + "/sheetjsw.xlsx";
await writeFile(file, wbout, 'ascii');
return file;
}
// highlight-end
const make_width = ws => {
```
< / TabItem >
< TabItem value = "EXPO" label = "EXPO" >
2023-05-01 01:27:02 +00:00
:::warning
2023-07-02 06:45:10 +00:00
At the time of testing, Expo Modules were incompatible with Android projects.
2023-01-05 23:33:49 +00:00
:::
Install `expo-file-system` and `expo-document-picker` dependencies:
```bash
npx install-expo-modules
npm i -S expo-file-system expo-document-picker
```
Add the highlighted lines to `index.js` :
```js title="index.js"
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
// highlight-start
import { read, write } from 'xlsx';
import { getDocumentAsync } from 'expo-document-picker';
import { documentDirectory, readAsStringAsync, writeAsStringAsync } from 'expo-file-system';
async function pickAndParse() {
const result = await getDocumentAsync({copyToCacheDirectory: true});
const path = result.uri;
const res = await readAsStringAsync(path, { encoding: "base64" });
return read(res, {type: 'base64'});
}
async function writeWorkbook(wb) {
const wbout = write(wb, {type:'base64', bookType:"xlsx"});
const file = documentDirectory + "sheetjsw.xlsx";
await writeAsStringAsync(file, wbout, { encoding: "base64" });
return file;
}
// highlight-end
const make_width = ws => {
```
< / TabItem >
< / Tabs >
5) Refresh the app:
```bash
cd ios
pod install
cd ..
```
Once refreshed, the development process must be restarted:
```bash
npx react-native run-ios
```
**iOS Testing**
The app can be tested with the following sequence in the simulator:
- Download < https: // sheetjs . com / pres . numbers >
- In the simulator, click the Home icon to return to the home screen
- Click on the "Files" icon
- Click and drag `pres.numbers` from a Finder window into the simulator.
![save file iOS ](pathname:///mobile/quasar7a.png )
- Make sure "On My iPhone" is highlighted and select "Save"
- Click the Home icon again then select the `SheetJSRN` app
- Click "Import data" and select `pres` :
![pick file iOS ](pathname:///mobile/rnios2.png )
Once selected, the screen should refresh with new contents:
![read file iOS ](pathname:///mobile/rnios3.png )
- Click "Export data". You will see a popup with a location:
![write file iOS ](pathname:///mobile/rnios4.png )
- Find the file and verify the contents are correct:
```bash
find ~/Library/Developer/CoreSimulator -name sheetjsw.xlsx |
while read x; do echo "$x"; npx xlsx-cli "$x"; done
```
Once testing is complete, stop the simulator and the development process.
**Android Testing**
There are no Android-specific steps. Emulator can be started with:
```bash
npx react-native run-android
```
![React Native Android App ](pathname:///mobile/rnand1.png )
The app can be tested with the following sequence in the simulator:
- Download < https: // sheetjs . com / pres . numbers >
- Click and drag `pres.numbers` from a Finder window into the simulator.
- Click "Import data" and select `pres.numbers` :
![pick file Android ](pathname:///mobile/rnand2.png )
Once selected, the screen should refresh with new contents:
![read file Android ](pathname:///mobile/rnand3.png )
- Click "Export data". You will see a popup with a location:
![write file Android ](pathname:///mobile/rnand4.png )
- Pull the file from the simulator and verify the contents:
```bash
adb exec-out run-as com.sheetjsrn cat files/sheetjsw.xlsx > /tmp/sheetjsw.xlsx
npx xlsx-cli /tmp/sheetjsw.xlsx
```
2023-07-02 06:45:10 +00:00
[^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)