i cant seem to get tailwind-rn to work on my app, i have tried all the suggestions made everywhere but still can't figure out whats wrong. CSS files and json are building properly when i run yarn build:tailwind.
Here is my code, please feel free to ask for more info...
App.js
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View } from "react-native";
import { useTailwind } from "tailwind-rn";
import { TailwindProvider } from "tailwind-rn";
import utilities from "./tailwind.json";
export default function App() {
const tw = useTailwind();
return (
<TailwindProvider utilities={utilities}>
<View style={tw("justify-center flex-1 items-center")}>
<Text style={tw("text-red-600 justify-center")}>
Open up App.js to start working on your!
</Text>
<StatusBar style="auto" />
</View>
</TailwindProvider>
);
}
Tailwind-config.js
module.exports = {
content: ["./*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [],
corePlugins: require("tailwind-rn/unsupported-core-plugins"),
};
My directory
I have tried all the recommendations here:
Why is my Tailwind ract native not changing anything?
the official GitHub repo for tailwind-rn.
I am expecting my app's UI to update using tailwind but nothing happens
Did you edit the global.css/input.css file to add these?
#tailwind base;
#tailwind components;
#tailwind utilities;
[EDIT April 19th]
I have created a CODESANDBOX to show the problem, of course, that doesn't occur in sandbox.
The only difference between this code and mine is that I have duplicated the code of the Button component in the SANDBOX example, whereas in my App the Button component is imported from a library (that belongs to the same yarn workspace as the app). The library is built with webpack and babel, excluding React and Material-UI
externals: {
react: "react",
"react-dom": "react-dom",
"react-router": "react-router",
"react-router-dom": "react-router-dom",
"#material-ui/core": "#material-ui/core",
"#material-ui/icons": "#material-ui/icons",
"#material-ui/lab": "#material-ui/lab",
"#material-ui/styles": "#material-ui/styles",
formik: "formik",
},
Inspecting the components in the Browser shows the difference when styling, between sandbox and my app :
on both sides, the class are applied to the component the same way:
in sandbox
in my app
but on sandBox, the MuiButtonBase-root background-color is overridden by the MuiButton-root background-color
whereas it is the opposite in my app. The MuiButton-root backGroundColor seems to be overriden bu the MuiButtonBase-root background-color
However, if I create a component RecreatedButton in the App by just importing the Button component of my UI Library, and re-exported it without changing anything (just passing a specific props the component is requested), then the styling is applied correctly, as in the sandbox example.
this is kind of weird to me...
Why such a behavior ?
just importing and rexporting as is the component
import {
Button as LibraryButton,
EButtonTypes,
IButtonProps,
} from "#mylibrairy/reactcomponentscommon"; <---- importing the button
import React from "react";
const RecreatedButton: React.FC<IButtonProps> = (
props: IButtonProps
): JSX.Element => {
return (
<LibraryButton type={EButtonTypes.BUTTON}>
{props.children}
</LibraryButton>
);
};
export { RecreatedButton };
Using both in app.ts. One got the theme, the other not
import { ThemeProvider } from "#material-ui/core/styles";
import {
Button as LibraryButton,
EButtonTypes,
IButtonProps,
} from "#mylibrairy/reactcomponentscommon"
import React from "react";
import AppBar from "../../UIComponents/AppBar";
import { RecreatedButton } from "../../UIComponents/Button";
import { MUITheme } from "./../../Theming/defaultTheme";
export const MainApp: React.FC = (): JSX.Element => {
return (
<ThemeProvider theme={MUITheme}>
<>
<AppBar />
<LibraryButton type={EButtonTypes.BUTTON}> I'm the library component, directly used as is, and background color is NOT CORRECT ></LibraryButton>
<RecreatedButton>
I'm recreated button, just rexporting the library component, and the backgroundcolor is correct !?!?{" "}
</RecreatedButton>
</>
</ThemeProvider>
);
};
finally I found one solution (not sure that it fixes the root cause as I still do not understand where it comes from).
I Guess it may helps some people here that are facing a similar issue with global theming in Material-Ui.
It turned out that I had to change the way to build my react/material-Ui components library #mylibrairy/reactcomponentscommon.
1- Make sure that in the library, all imports where such as import { Button} from "#material-ui/core" and not for example import Button from "#material-ui/core/Button"
2- Remove the usage of file-loader plugin in the .babelrc to make sure it doesn't change the way to import material-ui components
3- Push #material-ui/core and #material-ui/icons as a dev and peer dependencies in the package.json of the library.
4- Rebuilt the library using webpack and babel to compile typescript tsx to js.
All issues of priority seems to disappear (have done a lot of tests and checked in the chrome dev tools). In the example above, the .MuiButton-root class is well applied after the .MuiButtonBase-root one, thus overriding as expected the backgroundColor.
Would admit that I'm a little bit confused why this fixed the issue...
Rgds
For me, i just had to import "makeStyles" and "createStyles" from "#material-ui/core" not from "#material-ui/core/styles". i just did this and it fixed the issue but took me a lot of time to figure this out.
so import them like this:
import { makeStyles, createStyles } from "#material-ui/core";
not like this:
import { makeStyles, createStyles } from "#material-ui/core/styles";
You may try overriding default globals for MuiButtonBase
const theme = createMuiTheme({
props: {
// Name of the component ⚛️
MuiButtonBase: {
// The default props to change
root:{
backgroundColor: 'red'
}
},
},
});
function DefaultProps() {
return (
<ThemeProvider theme={theme}>
<Button>Change default props</Button>
</ThemeProvider>
);
}
Working sandbox here - https://codesandbox.io/s/override-button-base-7qwd5
I have a component in React which displays (or doesn't at the moment) an image within an src tag.
The file path & file name of the image is passed via props after being selected by the user, so I can't do an import at the top of the file. Apparently, I should be able to do something like src={require(file)} but this causes webpack to throw a hissy fit and give the following error: Error: cannot find module "."
As an e.g., a typical filepath/filename I pass to the component is: '../../../images/black.jpg'
This is a stripped-down version of the code in question:
import React, { Component } from "react";
class DisplayMedia extends Component {
render() {
return (
<div className="imgPreview">
<img src={this.props.file} alt="piccy" />
</div>
);
}
}
export default DisplayMedia;
Depending on your set up...
If the images are dynamic (during production, images will be added, edited, or deleted):
I'd recommend a microservice that only handles images. I go in depth on how to approach such a service: Image returned from REST API always displays broken
If the images are static (during production, the images are bundled within the "bundle.js" file):
- I'd recommend importing all of the images within the component, creating an array of the imported images, and then utilizing the array index and React state to cycle through them. For example:
import React, { Component } from "react";
import Image1 from "../images/Image1.png";
import Image2 from "../images/Image2.png";
import Image3 from "../images/Image3.png";
const images = [Image1, Image2, Image3];
export default class ShowImage extends Component {
state = { index: 0 };
handleChange = ({ target: { value } }) => {
this.setState({ index: value });
};
render = () => (
<div className="container">
<h1>Utilizing Array Indexes</h1>
<select
style={{ marginBottom: 20 }}
value={this.state.index}
onChange={this.handleChange}
>
{images.map((val,idx) => (
<option key={idx} value={idx}>Image {idx + 1}</option>
))}
</select>
<img src={images[this.state.index]} />
</div>
);
}
While I can't create an exact codesandbox of the above, this working example should give you the basic idea: https://codesandbox.io/s/ovoo077685
You don't need to add require in src. When relative path is used it will go the images availale in your server but when url is given image will be loaded. You can find more info here
When using src as /images/black.jpg it will convert to localhost:3000/images/black.jpg
I'm having difficulty with differences between client-side and server-side rendering of styles in Material-UI components due to classNames being assigned differently.
The classNames are assigned correctly on first loading the page, but after refreshing the page, the classNames no longer match so the component loses its styling. This is the error message I am receiving on the Console:
Warning: Prop className did not match.
Server: "MuiFormControl-root-3 MuiFormControl-marginNormal-4
SearchBar-textField-31"
Client: "MuiFormControl-root-3 MuiFormControl-marginNormal-4
SearchBar-textField-2"
I've followed the Material-UI TextField example docs, and their accompanying Code Sandbox example, but I can't seem to figure out what is causing the difference between the server and client classNames.
I experienced a similar issue when adding Material-UI Chips with a delete 'x' icon. The 'x' icon rendered with a monstrous 1024px width after refreshing. The same underlying issue being that icon was not receiving the correct class for styling.
There are a few questions on Stack Overflow addressing why the client and server might render classNames differently (e.g. need to upgrade to #Material-UI/core version ^1.0.0, using a custom server.js, and using Math.random in setState), but none of these apply in my case.
I don't know enough to tell whether this Github discussion might help, but likely not since they were using a beta version of Material-UI.
Minimal steps to reproduce:
Create project folder and start Node server:
mkdir app
cd app
npm init -y
npm install react react-dom next #material-ui/core
npm run dev
edit package.json:
Add to 'scripts': "dev": "next",
app/pages/index.jsx:
import Head from "next/head"
import CssBaseline from "#material-ui/core/CssBaseline"
import SearchBar from "../components/SearchBar"
const Index = () => (
<React.Fragment>
<Head>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
</Head>
<CssBaseline />
<SearchBar />
</React.Fragment>
)
export default Index
app/components/SearchBar.jsx:
import PropTypes from "prop-types"
import { withStyles } from "#material-ui/core/styles"
import TextField from "#material-ui/core/TextField"
const styles = (theme) => ({
container: {
display: "flex",
flexWrap: "wrap",
},
textField: {
margin: theme.spacing.unit / 2,
width: 200,
border: "2px solid red",
},
})
class SearchBar extends React.Component {
constructor(props) {
super(props)
this.state = { value: "" }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleSubmit(event) {
event.preventDefault()
}
render() {
const { classes } = this.props
return (
<form
className={classes.container}
noValidate
autoComplete="off"
onSubmit={this.handleSubmit}
>
<TextField
id="search"
label="Search"
type="search"
placeholder="Search..."
className={classes.textField}
value={this.state.value}
onChange={this.handleChange}
margin="normal"
/>
</form>
)
}
}
SearchBar.propTypes = {
classes: PropTypes.object.isRequired,
}
export default withStyles(styles)(SearchBar)
Visit page in browser localhost:3000 and see this:
red border around TextField component
Refresh the browser and see this:
TextField component's styles are gone
Notice that the red border around TextField disappears.
Relevant Libs:
"react": 16.4.0
"react-dom": 16.4.0
"next": 6.0.3
"#material-ui/core": 1.2.0
The problem is the SSR rendering in Next.js, which produces the style fragment before the page is rendered.
Using Material UI and Next.js (as the author is using), adding a file called _document.js solved the problem.
Adjusted _document.js (as suggested here):
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '#material-ui/styles'; // works with #material-ui/core/styles, if you prefer to use it.
import theme from '../src/theme'; // Adjust here as well
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
{/* Not exactly required, but this is the PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
};
};
This problem is related to MUI using dynamic class name which contain an ID. The IDs from the server side rendered CSS are not the same as the client side CSS, hence the mismatch error. A good start is to read the MUI SSR documentation
If you have this problem with nextjs (as I did) follow the example provided by the MUI team, which can be found here: material-ui/examples/nextjs
The most important part is in "examples/nextjs/pages/_app.js":
componentDidMount() {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}
the related ticket can be found here: mui-org/material-ui/issues/15073
what it does, is remove the server side rendered stylesheet and replace it by a new client side rendered one
The issue is the server side generates the class names but style sheets are not automatically included in the HTML. You need to explicitly extract the CSS and append it to the UI for the server side rendered components. The whole process is explained here: https://material-ui.com/guides/server-rendering/
There is one other important, separate issue here: Material UI V4 is not React Strict Mode compatible. Strict mode compatibility is slated for version 5 with the adoption of the Emotion style engine.
Until then, be sure you disable React Strict Mode. If you're using Next.js, this is turned on by default if you've created your app using create-next-app.
// next.config.js
module.exports = {
reactStrictMode: false, // or remove this line completely
}
I had the same problem with Next.js and styled component, with the transpilation by Babel. Actually, the class names are different on the client and the server side.
Fix it in writing this in your .babelrc :
{
"presets": ["next/babel"],
"plugins": [
[
"styled-components",
{ "ssr": true, "displayName": true, "preprocess": false }
]
]
}
I met this problem on Material-ui V5. The solution to fix this problem is to make sure that class name generator needs to behave identically on the server and on the client.
so adding the code below in your _app.js:
import { StylesProvider, createGenerateClassName } from '#mui/styles';
const generateClassName = createGenerateClassName({
productionPrefix: 'c',
});
export default function MyApp(props) {
return <StylesProvider generateClassName={generateClassName}>...</StylesProvider>;
}
// 1 . Warning: prop classname did not match. Material ui with React Next.js
// 2 . Use your customization css here
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
title: {
flexGrow: 1,
},
my_examle_classssss: {
with: "100%"
}
}));
// 3 . Here my Component
const My_Example_Function = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<Container>
<Examle_Component> {/* !!! Examle_Component --> MuiExamle_Component*/}
</Examle_Component>
</Container>
</div>
);
}
export default My_Example_Function
// 4. Add name parameter to the makeStyles function
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
title: {
flexGrow: 1,
},
my_examle_classssss: {
with: "100%"
},
}), { name: "MuiExamle_ComponentiAppBar" });
{/* this is the parameter you need to add { name: "MuiExamle_ComponentiAppBar" } */ }
{/* The problem will probably be resolved if the name parameter matches the first className in the Warning: you recive..
EXAMPLE :
Warning: Prop `className` did not match.
Server: "MuiSvgIcon-root makeStyles-root-98"
Client: "MuiSvgIcon-root makeStyles-root-1"
The name parameter will be like this { name: "MuiSvgIcon" }
*/ }
I like to share this mismatching case:
next-dev.js?3515:32 Warning: Prop className did not match. Server:
"MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-12
MuiSwitch-switchBase MuiSwitch-colorSecondary" Client:
"MuiButtonBase-root MuiIconButton-root PrivateSwitchBase-root-12
MuiSwitch-switchBase MuiSwitch-colorSecondary
PrivateSwitchBase-checked-13 Mui-checked"
On client there are two more classes which means that the behavior on client-side is different. In this case, this component shouldn't render on server-side. The solution is to dynamically render this component:
export default dynamic(() => Promise.resolve(TheComponent), { ssr: false });
I had a problem with different classNames for client and server. I was using React, Material-UI, makeStyles and SSR (server-side rendering).
The error was:
Warning: Prop `className` did not match. Server: "jss3" Client: "App-colNav-3"
I spent several hours before I figured out that I had discrepancy in webpack mode for client and server. The scripts in package.json were:
"devServer": "webpack --config webpack.server.config.js --mode=production --watch",
"devClient": "webpack --mode=development --watch",
After I changed both to have development mode, the problem was solved :)
"devServer": "webpack --config webpack.server.config.js --mode=development --watch",
"devClient": "webpack --mode=development --watch",
If somebody is still struggling even after trying above solutions, Try this
If you have used noSsr prop in any of your components or theme, then remove it.
I had the following config in mui theme object, which was causing this problem.
import { createTheme, responsiveFontSizes } from "#mui/material/styles";
let theme = createTheme({
components: {
MuiUseMediaQuery: {
defaultProps: {
noSsr: true,
},
},
},
palette: {
mode: "light",
common: {
black: "#000",
white: "#fff",
},
primary: {
main: "#131921",
contrastText: "#fff",
},
secondary: {
main: "#fb6a02",
contrastText: "#fff",
}
}
})
RemovingnoSSr fixed all of the issues in my app including style mismatch between client and server.
The problem is cause by Nextjs server side rendering. In order to solve I do as following:
Make a component to detect whether is it from Client side
import { useState, useEffect } from "react";
interface ClientOnlyProps {}
// #ts-ignore
const ClientOnly = ({ children }) => {
const [mounted, setMounted] = useState<boolean>(false);
useEffect(() => {
setMounted(true);
}, []);
return mounted ? children : null;
};
export default ClientOnly;
Wrap my page component using ClientOnly component
export default function App() {
return (
<ClientOnly>
<MyOwnPageComponent>
</ClientOnly>
);
}
So the idea is, if it is client side then only render the component on the page. Therefore if current rendering is from Client side, render <MyOwnPageComponent>, else render nothing
In my case the issue happened because of different compilation modes of webpack for client-side code and server-side: client's bundle was generated by webpack using "production" mode, while server ran some SSR code from a package optimized for "development". This created a different "className" hash in styled-components in generateAndInjectStyles():
if (process.env.NODE_ENV !== 'production') dynamicHash = phash(dynamicHash, partRule + i);
So my fix was just to align the webpack modes.
You can add the name in anywhere you use makeStyles, like this:
const useStyles = makeStyles({
card: {
backgroundColor: "#f7f7f7",
width: "33%",
},
title: {
color: "#0ab5db",
fontWeight: "bold",
},
description: {
fontSize: "1em"
}
}, { name: "MuiExample_Component" });
I am not sure how it works, but I found it here: Warning: Prop `className` did not match ~ Material UI css arbitrarily breaks on reload
I'm also using NextJS + MUI v5 and I ran into this exact error right after merging Git branches. I suspect the merge corrupted something in the cache. I deleted the contents of .next/ and restarted the dev server and the error went away.
#Leonel Sanches da Silva's answer didn't work for me, as #material-ui/styles is deprecated, but using a snippet I found for another (non-material UI) project seems to have worked just fine for me:
Hat tip to Raul Sanchez on dev.to for the answer to this one.
Next doesn't fetch styled-components styles on the server, to do that you need to add this page to pages/_document.js:
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
This code may update, so check Next's styled-components example for the latest.
Since the last 72 hours, I have lost my mind trying to figure this out.
All I want to do is use my vectors from illustrator and display them on my react-native app.
I tried a few libraries like react-native-vector-icons used icomoon followed steps, no result.
Please guide me a perfect solution to this issue. I have no web developer experience, all I know is Javascript and react-native and illustrator.
// Code
import React, {Component} from "react";
import {View, Text} from "react-native";
import {Font} from "expo";
import {createIconSetFromIcoMoon} from "react-native-vector-icons";
import icoMoonConfig from "../selection.json";
const Icon = createIconSetFromIcoMoon(icoMoonConfig);
Expo.Font.loadAsync("icomoon", require("../assets/fonts/icomoon.ttf"));
export default class INITIATE extends React.Component {
async componentDidMount() {
await Font.loadAsync("icomoon",
require("../assets/fonts/icomoon.ttf"));
this.setState({fontLoaded: true});
}
state = {
fontLoaded: true
};
render() {
return (
<View style={{
flex: 1, justifyContent: "center", alignItems:
"center"
}}>
{this.state.fontLoaded ? <Icon/> : null}
</View>
);
}
}
// The screen renders blank
React Native is for Android and iOS apps and React JS is for web development.
In React, import the SVG image first:
import sampleSvg from 'imgPath/sample.svg';
Then load it with:
<img src={sampleSvg} alt="A Sample SVG Image" />
For React Native, there's a similar question with an answer using webView.
Or try react-native-svg-uri
Hope it can help!
Using SVG icons with React is pretty simple.
Create an Icon component.
import IcoMoon from "react-icomoon";
import { Svg, Path } from "react-native-svg";
const iconSet = require("./selection.json");
const Icon = (props) => (
<IcoMoon
native
SvgComponent={Svg}
PathComponent={Path}
iconSet={iconSet}
{...props}
/>
);
export default Icon;
Import and use anywhere.
import Icon from "./icon";
<Icon icon="pencil" size={20} color="orange" />;
For more information: react-icomoon