With React Native, I'm looking to use StyleSheet to define a style and then use that style in numerous components, but I would like to change or override individual props for a few components. For example, a stack of 10 views with 5 different colors but all other props the same. Is this possible? What does the syntax look like?
I can't imagine I have to define 5 different styles or use in-line styling. Thanks very much for your help.
You can export some globally used styles from a single module, and import them wherever you need. Then to combine styles you can use the array syntax like [ styleA, styleB ].
So in a simple example you could do something like:
// ./styles.js
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
containerDefault: {
height: 100,
width: 300,
backgroundColor: 'black'
},
backgroundBlue: {
backgroundColor: 'blue'
},
backgroundGreen: {
backgroundColor: 'green'
}
});
And then...
// ./SomeComponent.js
import React from 'react';
import { View, Text } from 'react-native';
import styles from './styles';
const ComponentBlack = () => {
return (
<View style={styles.containerDefault}>
<Text>I should be black</Text>
</View>
);
};
const ComponentBlue = () => {
return (
<View style={[styles.containerDefault, styles.backgroundBlue]}>
<Text>I should be blue</Text>
</View>
);
};
const ComponentGreen = () => {
return (
<View style={[styles.containerDefault, styles.backgroundGreen]}>
<Text>I should be green</Text>
</View>
);
};
export default () => {
return (
<View>
<ComponentBlack />
<ComponentBlue />
<ComponentGreen />
</View>
);
};
Related
I'm using Material UI 5.10.11 and the MuiAlert component sometimes goes wrong.
This is what it should looks like when severity='error'
However in some pages, it looks like this
Below are my codes. Can anyone have a look at it and try to figure out what's wrong with my work?
import React, { useState, useEffect } from 'react';
import { Snackbar } from '#mui/material';
import MuiAlert from '#mui/material/Alert';
const Alert = React.forwardRef(function Alert(props, ref) {
return <MuiAlert elevation={24} ref={ref} variant="filled" {...props} />;
});
export default function MessageDialog(props) {
const defaultPosition = {
vertical: 'top',
horizontal: 'center'
};
const autoHideDuration = 5000;
const [open, setOpen] = useState(false);
useEffect(() => {
let timeoutId;
if (props.open) {
setOpen(true);
timeoutId = setTimeout(() => {
setOpen(false);
}, autoHideDuration);
}
return () => {
clearTimeout(timeoutId);
};
}, [props.open]);
return (
<>
<Snackbar
anchorOrigin={{
vertical: defaultPosition.vertical,
horizontal: defaultPosition.horizontal
}}
open={open}
>
<Alert severity={props.type} sx={{ width: '100%' }}>
{props.children}
</Alert>
</Snackbar>
</>
);
}
Many thanks in advance!
The fault is due to the css that I spotted out in the screenshots.
It looks like problem comes from Mui component class name which is MuiPaper-root. In page with white background it overrites because probably some other Mui components have same class name and you are using white background with this component or you have a css file with white background assigned to MuiPaper-root class in that page
In my React Native (Expo) application, I wanted to upgrade React Navigation from V5 to V6. However, I could not make TextInput in stack navigator header full-width. I tried 'auto' and '100%' for the width value in styling, however neither helped with a real wide textbox.
Here is the link for Expo snack for reproduction: https://snack.expo.io/#vahdet/reactnavigation6-headerbar and the App.js content from it is below. I guess I am short of some flexbox knowledge in headerSearchBarStyle:
import React, { useLayoutEffect, useState } from 'react';
import { Text, TextInput, View, StyleSheet } from 'react-native';
import { NavigationContainer, useNavigation } from '#react-navigation/native';
import { enableScreens } from 'react-native-screens';
import { AppearanceProvider } from 'react-native-appearance';
import { StatusBar } from 'expo-status-bar';
import { createStackNavigator } from '#react-navigation/stack';
enableScreens();
const HomeStack = createStackNavigator();
const Search = () => {
const navigation = useNavigation();
const [searchText, setSearchText] = useState('');
// Customize header
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: () => (
<TextInput
style={styles.headerSearchBarStyle}
value={searchText}
onChangeText={(val) => setSearchText(val)}
containerStyle={styles.searchBarContainerStyle}
placeholder="Search..."
returnKeyType="search"
textContentType="none"
cancelButtonTitle="Cancel"
/>
)
})
}, [navigation, searchText]);
return (
<View style={styles.view}>
{!searchText ? (
<Text>Search results go here</Text>
) : (
<Text>Initial (no search) content goes here</Text>
)}
</View>
)
}
const App = () => {
return (
<AppearanceProvider>
<StatusBar style="auto" />
<NavigationContainer>
<HomeStack.Navigator initialRouteName="Search">
<HomeStack.Screen name="Search" component={Search} />
</HomeStack.Navigator>
</NavigationContainer>
</AppearanceProvider>
);
}
const styles = StyleSheet.create({
headerSearchBarStyle: {
width: 'auto', // also tried '100%'
borderColor: 'black',
borderWidth: 1,
backgroundColor: 'transparent'
},
});
export default App;
EDIT: After Kartikey's approach I want to elaborate that by full-width, I do not necessarily mean the full screen width: There may be scenarios with headerLeft (e.g. back button) or headerRight components at the same time.
Use Device Width
import { Dimensions } from "react-native";
const ScreenWidth = Dimensions.get('window').width;
and
headerSearchBarStyle: {
width: ScreenWidth,
borderColor: 'black',
borderWidth: 1,
backgroundColor: 'transparent',
margin: 10,
},
You can also set it to width: ScreenWidth - 30, just to give some margin
Working Example
I'm writing some simple reusable component for our React(with MaterialUI) application.
The problem is, that i want to allow different styles of this same reusable component, to be customized via props, by the consuming component.
This is some of the code:
import { withStyles } from '#material-ui/core';
const styles = theme => ({
image: {
maxHeight: '200px'
}
});
render() {
const classes = this.props.classes
return (
<div>
...
<img className={classes.image} src={this.state.filePreviewSrc} alt="" />
...
</div>
);
}
Let's say, i want to allow the programmer to customize the appearance of classes.image. Can the hard-coded image class be overwritten somehow?
Is using withStyles api is even the correct approach, for creating components whose appearance can be customized by the consuming component/programmer?
There are three main approaches available for how to support customization of styles:
Leverage props within your styles
Leverage props to determine whether or not certain classes should be applied
Do customization via withStyles
For option 3, the styles of the wrapping component will be merged with the original, but the CSS classes of the wrapping component will occur later in the <head> and will win over the original.
Below is an example showing all three approaches:
ReusableComponent.js
import React from "react";
import { withStyles } from "#material-ui/core/styles";
const styles = {
root: props => ({
backgroundColor: props.rootBackgroundColor
? props.rootBackgroundColor
: "green"
}),
inner: props => ({
backgroundColor: props.innerBackgroundColor
? props.innerBackgroundColor
: "red"
})
};
const ReusableComponent = ({ classes, children, suppressInnerDiv = false }) => {
return (
<div className={classes.root}>
Outer div
{suppressInnerDiv && <div>{children}</div>}
{!suppressInnerDiv && (
<div className={classes.inner}>
Inner div
<div>{children}</div>
</div>
)}
</div>
);
};
export default withStyles(styles)(ReusableComponent);
index.js
import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "#material-ui/core/styles";
import ReusableComponent from "./ReusableComponent";
const styles1 = theme => ({
root: {
backgroundColor: "lightblue",
margin: theme.spacing(2)
},
inner: {
minHeight: 100,
backgroundColor: "yellow"
}
});
const Customization1 = withStyles(styles1)(ReusableComponent);
const styles2 = {
inner: {
backgroundColor: "purple",
color: "white"
}
};
const Customization2 = withStyles(styles2)(ReusableComponent);
function App() {
return (
<div className="App">
<ReusableComponent>Not customized</ReusableComponent>
<Customization1>Customization 1 via withStyles</Customization1>
<Customization2>Customization 2 via withStyles</Customization2>
<ReusableComponent rootBackgroundColor="lightgrey" suppressInnerDiv>
Customization via props
</ReusableComponent>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
So I'm trying to immitate the reddit text field implementation from material-ui, I've gone ahead and setup this custom component, but I'm getting a invalid hook call error everytime I run on the const classes=... Line
Here's the code:
import React, { Component } from "react";
import { TextField } from "#material-ui/core";
import { fade, makeStyles } from "#material-ui/core/styles";
import styles from "./LNTextField.module.css";
const useStylesReddit = makeStyles(theme => ({
root: {
border: "1px solid #e2e2e1",
overflow: "hidden",
borderRadius: 4,
backgroundColor: "#fcfcfb",
transition: theme.transitions.create(["border-color", "box-shadow"]),
"&:hover": {
backgroundColor: "#fff"
},
"&$focused": {
backgroundColor: "#fff",
boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 2px`,
borderColor: theme.palette.primary.main
}
},
focused: {}
}));
class LNTextField extends Component {
render() {
var classNames = require("classnames");
const classes = useStylesReddit();
return (
<TextField
InputProps={{ classes, disableUnderline: true }}
{...this.props}
/>
);
}
}
export default LNTextField;
Also since I just copied it I'm not sure how I can type this code in a seperate css files and refer to the hover and focused bits appropriately, so If you could also tell me how to do that that'd be great. Thanks!
According to React, you are getting this error because:
You can’t use Hooks inside of a class component
Convert your class component to functional component:
const LNTextField = props => {
var classNames = require("classnames");
const classes = useStylesReddit();
return (
<TextField
InputProps={{ classes, disableUnderline: true }}
{...props}
/>
);
}
// react-native example
import { StyleSheet, View } from 'react-native';
const styles = {
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
}
}
const stylesRN = StyleSheet.create(styles);
<View style={stylesRN.container}></View>
What the best way to reuse
// inner styles
{
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
}
in both react-native and react?
What i want to achieve in pseudocode (or another way of reuse in React):
<div style={magicAdapter(styles.container)}>Hello World!</div>
Problem: It is impossible to reuse all react-native inline-styles in react as is without magicAdapter.
What you could do is store all your styles in an object in some file e.g. const containerStyles = { borderRadius: 2 }, export it, then for React Native use the StyleSheets javascript class to create the styles for your div container
import {containerStyles} from '../someFile.js'
const styles = StyleSheets.create({
container: containerStyles
})
then for React you could do inline styling with the same object, but be aware that not all styles supported in StyleSheets can be used for inline styling, so if you want to do something equivalent there's libraries out there like emotion.js to dynamically load CSS in JS
https://github.com/emotion-js/emotion
Heres an example
import {css} from 'emotion'
import {containerStyle} from '../someFile'
const getContainerStyles = css`
border-radius: ${containerStyle.borderRadius}
`
export default class SomeClass extends Component {
render() {
return(
<div
style={getContainerStyles}
>
</div>
)
}
}
I hope this helps
You could concatenate the style of your new component with the style of container, like below
const styles = StyleSheet.create({
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
},
newComponent:{
// New component style
}
});
<View style={[styles.container, styles.newComponent]}>
</View>
// your component file name (button.js)
import React, { Component } from 'react';
// import the style from another file present in the same directory
import styles from 'button.style.js';
// you can reuse this style in another component also
class Button extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.buttonText}> Press Me! </Text>
</View>
);
}
}
export default Button;
// your style file name ( "button.style.js")
import { StyleSheet } from 'react-native';
export default StyleSheet.create({
container: {
padding: 10,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#43a1c9',
},
buttonText: {
fontSize: 20,
textAlign: 'center'
}
});