StylesProvider injectFirst Error: Element type is invalid: expected a string (for built-in components) or - material-ui

nextjs + material UI
Im sure its something basic that Im overlooking, but Im trying to override mui styles with css modules. The accepted method seems to be wrapping the component tree in a StylesProvider component and passing it a injectFirst attribute. When I do this though it generates the error
*Error: Element type is invalid: expected a string (for built-in components) or*
This is using nextjs. Package.json looks like:
#emotion/cache 11.4.0
#emotion/react 11.4.0
#emotion/server 11.4.0
#emotion/styled 11.3.0
#material-ui/core 5.0.0-beta.0
clsx 1.1.1
next 11.0.1
prop-types 15.7.2
react 17.0.2
react-dom 17.0.2
There is a codesandbox where you can see the error live and examine the code. Any ideas gratefully accepted.

Material UI began using emotion as styling library in v5, so as per the migration guide, the correct component to use is StyledEngineProvider. Like so:
import * as React from 'react';
import { StyledEngineProvider } from '#material-ui/core/styles';
export default function GlobalCssPriority() {
return (
<StyledEngineProvider injectFirst>
{/* Your component tree. Now you can override Material-UI's styles. */}
</StyledEngineProvider>
);
}

Related

Prop listed on the API doesn't exist on ImageList MUI component

I'm trying to use the ImageList component. I imported it as follows:
import { ImageList} from "#material-ui/core";
This works just fine. When I add the "variant" prop to the component, however, I start getting errors saying that I'm not matching any of the overloads. I see the variant prop used in their demos and on the API reference.
Error message
I suspect this has something to do with versioning -- I read something about ImageList being MUI v5 alpha. If that's the case I don't know what to do to fix my issue. The linker is finding the module just fine, so I don't know what's wrong.
I think I answered this myself. I was importing from the v4 version of MUI (#material-ui/core). I had to install v5 and import from here, instead:
import ImageList from '#mui/material/ImageList';
And then the variant prop worked. I was disheartened to find out that breakpoint props don't exist with this component, like they do with Grid. Instead, I had to use MUI's useMediaQuery hook to get the screen size and set the col prop accordingly.

Material-UI theme not working in shared-component

I'm building a reusable shared-component library using material-ui which is being imported in my main app like this:
import { theme, StepperComponent } from '#company/shared-components';
import { ThemeProvider } from '#mui/material/styles';
...
return (
<ThemeProvider theme={theme}>
<StepperComponent steps={stepperTitles} />
...
)
The stepper component is in my shared-components repository which I'm npm-linking
import React from 'react';
import Step from '#mui/material/Step';
import StepLabel from '#mui/material/StepLabel';
import { StyledStepper, StyledStepConnector, StyledStepIcon } from './Stepper.styles';
const StepperComponent = ({ steps, ...props }) => {
return (
<StyledStepper {...props} connector={<StyledStepConnector />} alternativeLabel>
However, for some reason the theme isn't getting applied to this component even though I'm wrapping it in the theme provider. When I log out the theme it doesn't include the colors that are in the theme being imported to my main app.
Does anyone know why this might be happening?
I'm dealing with something similar and haven't resolved it completely, but I have a strong feeling it involves multiple React contexts being created inside material-ui and emotion/react.
The ThemeProvider only exposes the theme to the components that have access to its context - the components within your main application.
I was able to achieve the desired behavior by making sure material-ui's ThemeProvider and it's context lives in the shared component library and not the main application. I did this by exporting a simple wrapper of ThemeProvider from the component library; literally just:
interface LibraryThemeProviderProps {
children?: React.ReactNode;
theme: Theme;
}
const LibraryThemeProvider: React.FC<LibraryThemeProviderProps> = ({ children, theme }) => (
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
)
and then using LibraryThemeProvider in the place of material's ThemeProvider in the main application.
If you want the same theme applied within your main application you only need to leave the original ThemeProvider in place alongside the new LibraryThemeProvider.
I'd prefer to solve this with a single ThemeProvider but haven't been able to yet :/
Note: I am using the useTheme hook inside all my components to access the theme. useTheme will use material's default theme if it doesn't see one provided by the ThemeProvider context - all this happens under the hood.
I have encountered the same problem recently. There were likely two copies of #mui/material loaded simultaneously.
If we symlinked the #company/shared-components package into main-app directly, all the packages defined in "devDependencies" will be included even though we have included them in "peerDependencies." Thus, resulting in the following dependency tree.
main-app
└─ node_modules
├─ #mui/material <-- ThemeProvider in the main app will load this
└─ #company/shared-components
└─ node_modules
└─ #mui/material <-- Components from shared-components will load this
In my case, the solution for Webpack is to include #mui/material in resolve.alias to mimic the notion of peer dependencies, which is to use the package installed in the main-app
resolve: {
alias: {
'#mui/material': 'node_modules/#mui/material'
}
}
Related Questions
MUI ThemeProvider is not injecting theme in a compiled component
How to create a shared component library with MUI 5

StylesProvider vs StyledEngineProvider in Material UI v5

I'm attempting to migrate from Material-UI v4 to v5 (currently in beta), but I'm not sure if I replace StylesProvider with StyledEngineProvider. There is no mention of it (see https://next.material-ui.com/guides/migration-v4/). The migration guide only mentions that StylesProvider should be imported directly from #material-ui/styles (instead of #material-ui/core/styles). It also mentions using StyledEngineProvider with the injectFirst option to take care of the css ordering. However, that is what StylesProvider does so I'm confused if I need to use StylesProvider or StyledEngineProvider.
Do I use StyledEngineProvider instead of StylesProvider? Or does it not matter because they both do the same thing? Or do I use StylesProvider if I am still using JSS and only use StyledEngineProvider if I no longer use JSS and only use Emotion? Any clarification would be appreciated.
Yep, I agree with those missing details among the two. After navigating over the repo, the difference is that StyledEngineProvider allows you to customize the current instance of StylesProvider used by MUI so by injecting Emotion first, JSS continues to work as before (<StyledEngineProvider injectFirst>).
It does matter which one you use, StylesProvider breaks the theme since you are creating your own provider without MUI's internal configuration, instead, StyledEngineProvider is only passing down a property to MUI's internal StylesProvider.
These APIs are offered as backward compatibility with V4, so it only affects JSS users. Currently, you can use both, but consider migrating your JSS styling to Emotion.
As in version 5.0.5, this should let you continue working with JSS:
import {
ThemeProvider,
StyledEngineProvider,
CssBaseline,
} from '#mui/material';
import {
createTheme
responsiveFontSizes,
} from '#mui/material/styles';
// import { StylesProvider } from '#mui/styles'; //breaks MUI theme!
const muiTheme = responsiveFontSizes(createTheme({/* your custom theme */}));
export const withJssAndCustomTheme = Component => props=>{
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={muiTheme}>
<CssBaseline/>
<Component
{...props}
/>
</ThemeProvider>
</StyledEngineProvider>
);
};
// withJssAndCustomTheme(App) // wrap your root component

Visual Studio Code with Native Script does not recognize all Native Script components

Visual Studio Code with Native Script does not recognise Native Script components sometimes in the component XML. I have one from the official tutorial and in it the ActionBar is recognized - but GridLayout is not:
'GridLayout' is not a known element:
1. If 'GridLayout' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component.
XML looks like this:
<ActionBar title="Groceries">
<!-- On iOS devices, <ActionItem>s are placed from left to right in sequence; you can override that (as the code above does) by providing an ios.position attribute. -->
<ActionItem text="Share" (tap)="share()" android.systemIcon="ic_menu_share_holo_dark" ios.systemIcon="9" ios.position="right"></ActionItem>
</ActionBar>
<GridLayout rows="auto, *">
<!-- add-bar necessary since we moved the page up 20 over the status bar on iOS-->
<GridLayout row="0" columns="*, auto" class="add-bar">
<TextField #groceryTextField [(ngModel)]="grocery" hint="Enter a grocery item" (returnPress)="add()" col="0"></TextField>
<Image src="res://add" (tap)="add()" col="1"></Image>
</GridLayout>...
It seems totally arbitrary since for example StackLayout is no problem in another XML in same project.
As suggested in the error log make sure that you have included NO_ERRORS_SCHEMA in the respective NgModule (if using lazily loaded modules include the schema there as well)
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
#NgModule({
schemas: [NO_ERRORS_SCHEMA],
//... more code follows here
Side note: it might be just an incomplete snippet but still... the parent GridLayout does not have an enclosing tag
In my case, it was happening just for one component html though NO_ERRORS_SCHEMA was included in respective module of that file, deleting and creating that file solved the issue for me strange but it did happen.

ReactJS : How to use "form" tag?

Hello everyone I'm trying to learn ReactJS and I would like to know why everybody is using tag to build forms.
I mean when I use this code:
import { TextInput, Form, View } from 'react-native'
<Form onSubmit={this.onSubmit}>
<TextInput/>
</Form>
I got this error :
Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined. You
likely forgot to export your component from the file it's defined in.
Or when I use this code :
import { TextInput, form, View } from 'react-native'
render (){
return (
<View>
<form onSubmit={this.onSubmit}>
<TextInput/>
</form>
</View>
);
}
I got this error :
Expected a component class, got [object Object].
I'm trying to fix and use a form but I'm mostly trying to understand how it works :)
Thank you for your time and your responses in advance.
Cheers
React-Native doesn't actually contain a Form tag.
There are libraries such as react-native-form-generator that provide similar functionality to what you are looking for.
Moreover, the error you're getting is trying to tell you exactly that - a class or function which defines a react component is expected where you specify a tag, but it was undefined, since there is no such component.