react dynamic component type example - reactjs

How/Where can i add types to the dynamic component Icons[name] ?
import * as Icons from "react-icons/fa";
const DynamicFaIcon = ({ name }: any) => {
const IconComponent = Icons[name];
return <IconComponent />;
};

You could just grap the keys from the import, since its a JS object like any other:
import * as Icons from "react-icons/fa";
const DynamicFaIcon = ({ name }: {name: keyof typeof Icons}) => {
const IconComponent = Icons[name];
return <IconComponent />;
};
I would be careful about importing literally everything from that package though. There's over 1,500 components in there, does any application actually make use of all of them? You'll end up bundling way more than you need.

This is my answer on dynamic icons problem, is it your question answer ?? , maybe it will help you, use it like this `
import React from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import {library} from '#fortawesome/fontawesome-svg-core';
import * as Icons from '#fortawesome/free-solid-svg-icons';
const iconList = Object.keys(Icons)
.filter((key) => key !== 'fas' && key !== 'prefix')
.map((icon) => Icons[icon]);
library.add(...iconList);
const Feature = ({ carFeature }) => {
console.log(carFeature);
return (
<div>
<FontAwesomeIcon icon={carFeature?.icon} color="#ddd" />
<h3>{carFeature?.name}</h3>
<p>{carFeature?.desc}</p>
</div>
);
};
export default Feature;
If no then try this
Not the OP's direct issue but for users encountering this error for libraries not under their control, one can suppress this error is by adding:
{
...
"suppressImplicitAnyIndexErrors": true,
...
}
to the tsconfig.json file.
Read more here Question Answer

Related

Autocomplete and method descriptions for imported packages in monaco-editor/react

I am trying to add an in-browser IDE to a React app using #monaco-editor/react. Within the code editor I want users to be able to import Playwright and I want autocomplete and syntax highlighting to be correct for the various Playwright functions and types. No matter what I try I cannot get this to work. I cannot even get the editor element to not mark the import of Playwright as an error.
Within this code snippet codeTemplate is just a set of placeholder code for the editor, and ../../frameworkType/playwright.d.ts is a file housing the types file from when you install playwright-core.
import Editor, { EditorProps } from "#monaco-editor/react";
import { Box } from "#mui/material";
import { useRef } from "react"
import { codeTemplate } from "../../constants/constants";
// eslint-disable-next-line import/no-webpack-loader-syntax
const playwrightTypings = require("!!raw-loader?esModule=false!../../frameworkTypes/playwright.d.ts");
export const CodeEditor = ({ ...props }: EditorProps) => {
const monacoRef = useRef(null);
const types = [
{ name: "playwright", types: playwrightTypings },
];
const handleEditorWillMount = (monaco: any) => {
types.forEach(module => {
monaco.languages.typescript.javascriptDefaults.addExtraLib(
`declare module "${module.name}" {
${module.types}
}`
)
});
};
const handleEditorDidMount = (editor: any, monaco: any) => {
monacoRef.current = editor;
};
return (
<Box display="flex">
<Editor
height="45vh"
width="100%"
language="typescript"
theme="vs-dark"
defaultValue={codeTemplate}
beforeMount={handleEditorWillMount}
onMount={handleEditorDidMount}
{...props}
/>
</Box>
);
}
Any advice would be massively appreciated. I've been banging my head against it for days.
I have built my attempted solution based off of these two resources but have had no luck.
install packages and get autocompletion on Monaco editor react
https://blog.checklyhq.com/customizing-monaco/

Inserting Middleware(insights) with Instantsearch react

So, we have a functional search with Algolia/Instantsearch/React/Nextjs. But the Insights middleware is currently not setup.
Below is a trimmed version of the implementation, we use custom widgets to have more fine control over the display of results.
We use the hooks implementation for the custom widgets like so
const { hits, sendEvent, ... } = useInfiniteHits(props)
import { useState } from 'react'
import algoliasearch from 'algoliasearch/lite'
import { InstantSearch, InstantSearchSSRProvider } from 'react-instantsearch-hooks-web'
import SearchBox from '#components/swatches/algolia/SearchBox'
import Hits from '#components/swatches/algolia/Hits'
import RefinementList from '#components/swatches/algolia/RefinementList'
import CurrentRefinements from '#components/swatches/algolia/CurrentRefinements'
import { getServerState } from 'react-instantsearch-hooks-server'
import Container from 'react-bootstrap/Container'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import { history } from 'instantsearch.js/es/lib/routers/index.js'
import styles from '#styles/page.module.scss'
const Page = ({ serverState, url }) => {
const searchClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_INDEX_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
)
return (
<div className={styles.wrapper}>
<InstantSearchSSRProvider {...serverState}>
<InstantSearch
searchClient={searchClient}
indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX}
routing={{
router: history({
getLocation: () =>
typeof window === 'undefined' ? new URL(url) : window.location,
}),
}}
>
<Container fluid="lg">
<div className="mb-3">
<SearchBox />
</div>
<CurrentRefinements />
<Hits />
</Container>
</InstantSearch>
</InstantSearchSSRProvider>
</div>
)
}
export default Page
export async function getServerSideProps({ req, res, resolvedUrl}) {
const protocol = req.headers.referer?.split('://')[0] || 'https';
const url = `${protocol}://${req.headers.host}${req.url}`;
const serverState = await getServerState(<Page url={url} />);
return {
props: {
serverState,
url,
},
}
}
So my question is, where do we hook up the insights middleware for this specific implementation?
Reading the docs, (https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/) I'm not really 100% sure where to start. I can't find anywhere in the instantsearch react docs where it references anyway to configure that sort of thing.
Am I better of just firing events at the API directly instead of with InstantSearch?
Thanks
The trick is finding the InstantSearch instance using useInstantSearch:
const instantSearch = useInstantSearch();
instantSearch.use(middleware)
The docs should tell you what to do from there.

Gatsby - Uncaught TypeError - Context/build problem

I was developing my application in Gatsby and got stuck. Everything is working fine with "gatsby develop", but when I run "gatsby build" I get an error:
"WebpackError: TypeError: Cannot destructure property 'cursorStyles' of 'Object(...)(...)' as it is undefined."
And yeah, cursorStyles are defined in the context, so everything should work perfectly or I am missing something. Tried to clean cache, but still the error occurs, which is very weird cuz didn't have any problems to work on this project locally.
EDIT - yes, I wrapped the gatsby application with the Global Provider as you can see below. I just don't understand why the build doesn't work, when I clearly have the access to the context... ;/
gatsby-browser.js
import React from "react"
import { GlobalProvider } from "./src/context/globalContext"
export const wrapRootElement = ({ element }) => {
return <GlobalProvider>{element}</GlobalProvider>
}
Context - values are defined in global provider const
import React, { createContext, useReducer, useContext } from "react"
//Define Context
const GlobalStateContext = createContext()
const GlobalDispatchContext = createContext()
//Reducer
const globalReducer = (state, action) => {
switch (action.type) {
case "TOGGLE_THEME": {
return {
...state,
currentTheme: action.theme,
}
}
case "CURSOR_TYPE": {
return {
...state,
cursorType: action.cursorType,
}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(globalReducer, {
currentTheme: "dark",
cursorType: false,
cursorStyles: ["pointer", "hovered", "locked", "white"],
})
return (
<GlobalDispatchContext.Provider value={dispatch}>
<GlobalStateContext.Provider value={state}>
{children}
</GlobalStateContext.Provider>
</GlobalDispatchContext.Provider>
)
}
//custom hooks for when we want to use our global state
export const useGlobalStateContext = () => useContext(GlobalStateContext)
export const useGlobalDispatchContext = () => useContext(GlobalDispatchContext)
Layout.js - problem occurs when destructuring and using my custom hook
import React, {useState} from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import { createGlobalStyle, ThemeProvider } from "styled-components"
import { normalize } from "styled-normalize"
import Header from './header'
import Cursor from './customCursor'
import Navigation from './navigation'
import { useGlobalStateContext, useGlobalDispatchContext } from '../context/globalContext'
const Layout = ({ children }) => {
const { cursorStyles, currentTheme } = useGlobalStateContext()
const dispatch = useGlobalDispatchContext()
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
const darkTheme = {
background: '#000',
text:'#fff',
red: '#ea291e'
}
const lightTheme = {
background: '#fff',
text:'#000',
red: '#ea291e'
}
const onCursor = cursorType => {
cursorType = (cursorStyles.includes(cursorType) && cursorType || false)
dispatch({ type: "CURSOR_TYPE", cursorType: cursorType})
}
const [toggleMenu, setToggleMenu] = useState(false)
return(
<ThemeProvider theme={currentTheme === "dark" ? darkTheme : lightTheme}>
<GlobalStyle/>
<Cursor toggleMenu={toggleMenu} />
<Header onCursor={onCursor} toggleMenu={toggleMenu} setToggleMenu={setToggleMenu} />
<Navigation onCursor={onCursor} toggleMenu={toggleMenu} setToggleMenu={setToggleMenu} />
<main>{children}</main>
{console.log(currentTheme)}
</ThemeProvider>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
Finally I solved it! I don't know why, but I guess it's just Gatsby who works in a mysterious way. I duplicated my code from gatsby-browser, and put exactly the same thing into the gatsby-ssr file and... surprisingly the weird errors about "object undefined" disappeared.
Unfortunately, due to the fact that gatsby build in that case works similar to the next.js' server-side rendering, I had to fix my code in different places - e.g "window" properties had to be rendered conditionally - but duplicating gatsby-browser's code to the gatsby-ssr fixed the building problem! So as I thought, it wasn't a problem with my code, but rather a problem with gatsby's config.
Very strange. This problem happens only in production. Duplicating the code from gatsby-browser inside gatsby-ssr - really solves it!
import React from 'react';
import CartProvider from './src/components/CartProvider';
export const wrapRootElement = ({ element }) => (
<CartProvider>{element}</CartProvider>
);

NextJS issue with server side rendering with react-d3-tree

To start off, I have looked at issue number 40 and 95 on the react-d3-tree github
I don't see anything on StackOverflow that would help me. I am trying to implement the parseJSON method so I can take my own JSON file from the project folder and then generate a tree diagram.
Let's start from what I did in the beginning. I copy pasted the example code which worked for 2 seconds before crashing. Reason? Server Side Rendering. Great, so then I find this from NextJS which allows me to disable SSR for some components. Hey, now the example code is working. Let's try the example code where they use external data! Nope, it can't find the parseJSON method. I have no idea what to do, can't find anything to fix this. I am trying to import this function that has some issue with SSR, but because it isn't a component I am not able to import it using dynamic, and I can't import normally because it causes a "window is not defined" error because of SSR.
The following are my main two files.
DynamicComponent.js [Version 1]
import dynamic from 'next/dynamic';
const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export default Tree;
DynamicComponent.js [Version 2]
import dynamic from 'next/dynamic';
export const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export const treeUtil = dynamic(
() => import('react-d3-tree/src/util'),
{ ssr: false },
);
Diagram/index.js
import React from 'react';
import { Tree, treeUtil } from '../DynamicComponent';
const myTreeData = require('../fakeData.json');
class Diagram extends React.PureComponent {
constructor() {
super();
this.state = {
data: undefined,
};
}
componentWillMount() {
treeUtil.parseJSON(myTreeData)
.then((data) => {
this.setState({ data });
});
}
render() {
return (
<div
id="treeWrapper"
style={{ width: '50em', height: '20em' }}
>
<Tree data={this.state.data} />
</div>
);
}
}
export default Diagram;
Error I Get with Version 1
ReferenceError: treeUtil is not defined
Error I Get with Version 2
TypeError: _DynamicComponent__WEBPACK_IMPORTED_MODULE_1__.treeUtil.parseJSON is not a function
Please StackOverflow, you're my only hope.
I ran into the same problem with Cytoscape, a similar library (but specifically for graph-network visualization). It took lots of trial and error, but the solution was:
import the component dynamically
remove the import JSON and inline it into a js file. For some stupid reason, that worked for me and was the magic fix. (how big was your JSON file?) Worse-case try copying & pasting into the component itself.
For your component try this:
// convert fakeData.json to fakeData.js
export default {...fake data here };
import React from 'react';
import dynamic from 'next/dynamic'
import myTreeData from 'fakeData';
const Tree = dynamic(
() => import('./dynamicComponent'),
{ ssr: false }
);
// you can also delineate a loading component;
// converted to hooks for '21
const Diagram = () => {
const [data,setData] = useState({});
useEffect(() => {
treeUtil.parseJSON(myTreeData)
.then((data) => {
setData(data);
})
},[treeUtil,myTreeData,setData]);
return (
<div
id="treeWrapper"
style={{ width: '50em', height: '20em' }}
>
<Tree data={data} />
</div>
);
}
export default Diagram;
I guess treeUtil is not a react component, so you can't use dynamic to import it. Just import it normally may be work.
import dynamic from 'next/dynamic';
export const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export { default as treeUtil } from 'react-d3-tree/src/util';

Using React.lazy with TypeScript

I am trying to use React.lazy for code splitting in my TypeScript React app.
All I am doing is changing that line:
import {ScreensProductList} from "./screens/Products/List";
to this line:
const ScreensProductList = lazy(() => import('./screens/Products/List'));
But the import('./screens/Products/List') part triggers a TypeScript error, stating:
Type error: Type 'Promise<typeof import("/Users/johannesklauss/Documents/Development/ay-coding-challenge/src/screens/Products/List")>' is not assignable to type 'Promise<{ default: ComponentType<any>; }>'.
Property 'default' is missing in type 'typeof import("/Users/johannesklauss/Documents/Development/ay-coding-challenge/src/screens/Products/List")' but required in type '{ default: ComponentType<any>; }'.
I am not quite sure what I am supposed to do here to get it to work.
You should do export default class {...} from the ./screens/Products/list instead of export class ScreensProductList {...}.
Or, alternatively, you can do:
const ScreensProductList = lazy(() =>
import('./screens/Products/List')
.then(({ ScreensProductList }) => ({ default: ScreensProductList })),
);
One option is to add default export in "./screens/Products/List" like that
export default ScreensProductList;
Second is to change import code to
const ScreensProductList = React.lazy(() =>
import("./screens/Products/List").then((module) => ({
default: module.ScreensProductList,
}))
);
Or if you don't mind using an external library you could do:
import { lazily } from 'react-lazily';
const { ScreensProductList } = lazily(() => import('./screens/Products/List'));
Another solution would be:
1. Import using lazy
const ScreensProductList = lazy(() => import('./screens/Products/List'));
2. Set the type on the export
React hooks
import { FunctionComponent /*, FC */ } from 'react';
const List = () => (
return </>;
);
export default List as FunctionComponent; // as FC;
React class components
import { Component, Fragment, ComponentType } from 'react';
class List extends Component {
render() {
return <Fragment />;
}
}
export default List as ComponentType;
This is the proper syntax. It works also in the Webstorm IDE (the other syntaxes shown here are still showing a warning)
const ScreensProductList = React.lazy(() => import("./screens/Products/List").then(({default : ScreensProductList}) => ({default: ScreensProductList})));
const LazyCart = React.lazy(async () => ({ default: (await import('../Components/market/LazyCart')).LazyCart }))
You can create an index.ts file where you can export all your components like in this eg. :
export {default as YourComponentName} from "./YourComponentName";
After that you can use React.lazy:
React.lazy(() => import("../components/folder-name-where-the-index-file-is-created").then(({YourComponentName}) => ({default: YourComponentName})))
Just to expand on this answer. This also works for the dynamic imports.
const Navbar = dynamic(() => import('../components/Navbar'), {
ssr: false,
});
Where Navbar is a default exported component.
const Navbar = () => ()
export default Navbar

Resources