I'm developing a web compiler in TypeScript and I've encountered a small, but still irritating issue.
I have a progress bar inside an iframe element which keeps rendering for a short amount of time. I want that progress bar to be rendered only when there's a code bundling process.
Here's a piece of that TypeScript code:
codeCell.tsx (The CodeCell component):
const bundle = useTypedSelector((state) => state.bundles[cell.id]);
return (
<>
<Resizable direction="vertical">
<div className="h-100 d-flex flex-row position-relative">
<Resizable direction="horizontal">
<div className="position-relative w-100">
<CodeEditor
initialValue={cell.content}
onChange={handleEditorChange}
/>
</div>
</Resizable>
<div className="progress-wrapper">
{!bundle || bundle.loading ? (
<div className="progress-cover">
<progress hidden={!bundle} max="100"/>
</div>
) : (
<Preview code={bundle.code} err={bundle.err} cell={cell}/>
)}
</div>
</div>
</Resizable>
</>
);
useTypedSelector.ts (useTypedSelector hook):
export const useTypedSelector: TypedUseSelectorHook<RootState> = (selector) => {
const result = useSelector(selector, shallowEqual);
return useMemo(() => result, [result]);
};
const shallowEqual = (a: any, b: any) => {
if (a === undefined || b === undefined) {
return false;
}
for (let key in a) {
if(a[key] !== b[key]) {
return false;
}
}
for (let key in b) {
if (!(key in a)) {
return false;
}
}
return true;
};
preview.tsx (Preview component):
interface PreviewProps {
code: string;
err: string;
cell: Cell;
}
const Preview: React.FC<PreviewProps> = ({ code, err, cell }) => {
const iframe = useRef<any>();
useEffect(() => {
iframe.current.srcdoc = html;
setTimeout(() => {
iframe.current.contentWindow.postMessage(code, '*'); // Posts the result from the code bundling
}, 10);
}, [code]);
return (
<div className="preview-wrapper">
<iframe
title="code preview"
ref={iframe}
sandbox="allow-scripts"
srcDoc={html}/>
{err && (
<div className="preview-error">
{err}
</div>
)}
<div style={{ display: "none" }}>
<div className="action-bar">
<ActionBar id={cell.id}/>
</div>
</div>
</div>
);
}
export default Preview;
One of the approaches I tried is using a ternary operator inside the Preview component's props stating that if there's a code bundling process you'll see the progress bar (the same if there's a code error) and if not (there's no code at all), you'll see an empty string (meaning you'll see an empty iframe element).