My use of `<PDFViewer style={PDFStyles.viewer}>` results in error that does not exist when just using `<Document>`
Describe the bug New to most of the below, and wanted to conditionally render a Fluent UI Icon [checkbox].
Using <PDFViewer style={PDFStyles.viewer}> results in error that does not exist when just using <Document>
Error - "Invalid '' string child outside <Text>"
To Reproduce
Run the code below with <PDFViewer style={PDFStyles.viewer}> the error appears – along with not formatted in rows [I believe caused by the fact that it stops rendering on error]
You can make use of react-pdf REPL to share the snippet
REPL did not provide <PDFViewer> so am providing all code below [apologies]
import React, { Fragment, useEffect, useState } from "react";
import { Image, Font, Document, Page, Text, View, StyleSheet, PDFViewer } from '@react-pdf/renderer';
import type { IPciSelfAssessmentsProps } from './IPciSelfAssessmentsProps';
//https://github.com/microsoft/fluentui/wiki/Using-icons#alternative-cdn-options
import { registerIcons } from '@fluentui/react/lib/Styling';
import { ChevronDownIcon } from '@fluentui/react-icons-mdl2';
registerIcons({
icons: {
ChevronDown: <ChevronDownIcon />
}
});
import { Icon } from '@fluentui/react/lib/Icon';
export const PciSelfAssessments: React.FC<IPciSelfAssessmentsProps> = (props) => {
const { description, isDarkTheme, environmentMessage, hasTeamsContext, userDisplayName, spfxContext, } = props;
const [tableData, setTableData] = useState<{ column: string[], data: any[] }>({ column: [], data: [] });
// const logo = require('../assets/Checkmark.jpg');
const data = {
"column": [
"status",
"price",
"email",
"time"
],
"data": [
{
"status": "completed",
"price": "1",
"email": "@.com",
"time": "12:45"
},
{
"status": "not completed",
"price": "",
"email": "",
"time": ""
}
]
}
const PDFStyles = StyleSheet.create({
rowView: {
display: 'flex', flexDirection: 'row', border: '1px solid #EEE', paddingTop: 8, paddingBottom: 8, textAlign: "center"
},
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4',
color: "black",
},
section: {
margin: 10,
padding: 10,
flexGrow: 1,
},
viewer: {
display: 'flex', flexDirection: 'row',
width: window.innerWidth,
height: window.innerHeight,
}
});
useEffect(() => {
if (data !== undefined) setTableData(data);
}, []);
//https://stackoverflow.com/users/20434644/yolomama
return (
<>
{tableData.data.length > 0 ? (
<PDFViewer style={PDFStyles.viewer}>
<Document>
<Page size={"A4"} style={PDFStyles.page}>
<View style={PDFStyles.rowView}>
{tableData["column"].map((c: any) => <Text style={{
width: `${100 / tableData["column"].length}%`
}}>{c}</Text>)}
</View>
{tableData["data"].map((rowData: any) => <>
<View style={PDFStyles.rowView} >
{tableData["column"].map((c: any) => {
switch (c) {
case "status":
if (rowData[c] === "completed") {
return [<Text style={{ width: `${100 / tableData["column"].length}%` }}><Icon iconName="CheckboxComposite" /></Text>];
} else {
return [<Text style={{ width: `${100 / tableData["column"].length}%` }}>{<Icon iconName="Checkbox" />}</Text>];
}
break;
default:
return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
}
}
)}
</View>
</>)}
</Page >
</Document>
</PDFViewer>
) : <></>}
</>
);
}
Package.json { "name": "pci-self-assessments", "version": "0.0.1", "private": true, "engines": { "node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0" }, "main": "lib/index.js", "scripts": { "build": "gulp bundle", "clean": "gulp clean", "test": "gulp test", "serve": "fast-serve" }, "dependencies": { "@fluentui/react": "^8.118.4", "@fluentui/react-icons": "^2.0.240", "@fluentui/react-icons-mdl2": "^1.3.66", "@fortawesome/free-solid-svg-icons": "^6.5.2", "@microsoft/sp-component-base": "1.18.2", "@microsoft/sp-core-library": "1.18.2", "@microsoft/sp-lodash-subset": "1.18.2", "@microsoft/sp-office-ui-fabric-core": "1.18.2", "@microsoft/sp-property-pane": "1.18.2", "@microsoft/sp-webpart-base": "1.18.2", "@pnp/core": "^4.0.1", "@pnp/graph": "^4.0.1", "@pnp/logging": "^4.0.1", "@pnp/queryable": "^4.0.1", "@pnp/sp": "^3.6.0", "@pnp/sp-commonjs": "^2.15.0", "@pnp/spfx-controls-react": "3.18.0", "@react-pdf/layout": "3.6.4", "@react-pdf/renderer": "3.1.15", "immer": "^10.1.1", "react": "17.0.1", "react-dom": "17.0.1", "tslib": "2.3.1" }, "overrides": { "@react-pdf/layout": "3.6.4", "@react-pdf/textkit": "4.2.1" }, "devDependencies": { "@microsoft/eslint-config-spfx": "1.18.2", "@microsoft/eslint-plugin-spfx": "1.18.2", "@microsoft/rush-stack-compiler-4.7": "0.1.0", "@microsoft/sp-build-web": "1.18.2", "@microsoft/sp-module-interfaces": "1.18.2", "@rushstack/eslint-config": "2.5.1", "@types/react": "17.0.45", "@types/react-dom": "17.0.17", "@types/webpack-env": "~1.15.2", "ajv": "^6.12.5", "eslint": "8.7.0", "eslint-plugin-react-hooks": "4.3.0", "gulp": "^4.0.2", "spfx-fast-serve-helpers": "~1.18.0", "typescript": "4.7.4" } }
Gulpfile.js
"use strict";
const build = require("@microsoft/sp-build-web");
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
var result = getTasks.call(build.rig);
result.set("serve", result.get("serve-deprecated"));
return result;
};
build.tslintCmd.enabled = false;
/* fast-serve */
const { addFastServe } = require("spfx-fast-serve-helpers");
addFastServe(build);
/* end of fast-serve */
build.initialize(require('gulp'));
build.configureWebpack.mergeConfig({
additionalConfiguration: (wpcfg) => {
// if dev build, mod config for profiling react
if (wpcfg.mode === "development") {
// add alias for the react-dom profiler
wpcfg.resolve.alias = {
"react-dom$": "react-dom/profiling",
};
// remove externalization of react & react-dom
wpcfg.externals = wpcfg.externals.filter((external) => {
return external !== "react" && external !== "react-dom";
});
}
return wpcfg;
},
});
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfig) => {
### **generatedConfig.resolve.extensions = [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json"],**
console.log('<webpack.config type="object">');
console.log(generatedConfig);
console.log('</webpack.config>');
console.log('<webpack.config type="string">');
console.log(JSON.stringify(generatedConfig));
console.log('</webpack.config>');
return generatedConfig;
}
});
Expected behavior A clear and concise description of what you expected to happen. Expected to render per first print screen , but within the <PDFViewer> control
Screenshots Rendered without PDFViewer
Rendered using PDFViewer
minor update on this, I was able to get the checkmark to render with the code below - but it still is not displaying in a table format as it does without <PDFViewer>
return (
<>
{tableData.data.length > 0 ? (
<PDFViewer style={PDFStyles.viewer}>
<Document>
<Page size={"A4"} style={PDFStyles.page}>
<View style={PDFStyles.rowView}>
{tableData["column"].map((c: any) => <Text style={{
width: `${100 / tableData["column"].length}%`
}}>{c}</Text>)}
</View>
{tableData["data"].map((rowData: any) => <>
<View style={PDFStyles.rowView} >
{tableData["column"].map((c: any) => {
switch (c) {
case "status":
if (rowData[c] === "completed") {
return <Image style={PDFStyles.image} source={require("../assets/Checkmark.jpg")} />;
} else {
return <Image style={PDFStyles.image} source={require("../assets/Checkmark.jpg")} />;
}
break;
default:
return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
}
/*
switch (c) {
case "status":
if (rowData[c] === "completed") {
return [<Text style={{ width: `${100 / tableData["column"].length}%` }}><Icon iconName="CheckboxComposite" /></Text>];
} else {
return [<Text style={{ width: `${100 / tableData["column"].length}%` }}>{<Icon iconName="Checkbox" />}</Text>];
}
break;
default:
return <Text style={{ width: `${100 / tableData["column"].length}%` }}>{rowData[c]}</Text>;
}
*/
}
)}
</View>
</>)}
</Page >
</Document>
</PDFViewer>
) : <></>}
</>
);
}
I think that i fixed it [bar some formatting issues] by changing page style from row to column
page: {
flexDirection: 'column',
backgroundColor: '#E4E4E4',
color: "black",
},
HI how to managed the
Invalid '' string child outside <Text> component
I'm stuck with that too
HI how to managed the
Invalid '' string child outside <Text> componentI'm stuck with that too
Are you using logical conditional rendering on some of your compents with the && AND operator? If so, this will return undefined instead of null and cause the renderer to throw the error you have seen.
Change your conditional rendering to ternary conditionals:
// CHANGE THIS
{value && (
<View style={{ fontWeight: "bold", marginRight: 20 }}>
<Text>{value}</Text>
</View>
)}
// TO THIS
{value ? (
<View style={{ fontWeight: "bold", marginRight: 20 }}>
<Text>{value}</Text>
</View>
) : null}
I hope this works for you. It just solved my issues today!