I'm very new to react. And I'm trying to learn some new stuff. So what I want to do is to add CSS within my Header.js file, And I don't know how to do that. Because I don't want to import external or inline CSS. But rather use it like in Html with tag on the header. But not just that, I want to use that CSS specifically for the file, in this case, Header.js.
This might help
Header.js
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
// alignSelf: 'center',
},
textStyle: {
marginTop: Metrics.ratio(0),
marginHorizontal: Metrics.ratio(70),
fontFamily: Fonts.type.base,
fontSize: Fonts.size.normal,
color: Colors.black,
},
});
class Header extends React.Component {
render() {
return (
<div style={ styles.color } />
);
}
}
You have several possibilites.
The simplest is to use css code directly in the element like
<div style={{color:'#000',backgroundColor:'#fff'}}>
...
</div>
Or you can use the libraries for that, like styled-components (https://styled-components.com/) for this.
You need to import this:
import styled from 'styled-components';
Then you can define your element css on the top of the page, i.e. SomeCSSStyling
const SomeCSSStyling = styled.div`
color:#000;
background-color:#fff;
`
Then you can use this constant in the class code of the react component:
class MyReactComponent extends Component {
constructor(props) {
...
}
render() {
return (
<SomeCSSStyling>
...
</SomeCSSStyling>
);
}
}
export default MyReactComponent;
UPDATE:
You can also define :hover or ::before etc. with style-components:
const SomeCSSStyling = styled.div`
color:#000;
background-color:#fff;
&:hover{
font-weight:bold;
}
`
You can create style object inside react component like this:
const myDivStyles = {
color: "red",
fontSize: "32px"
}
All propertis are the same like in CSS but this one with "-" sign change in to camelCase nams, e.g. font-size change to fontSize, background-color change to backgroundColor.
Then you can add this style to elements in your components by style attribute.
render() {
return (
<div style={ myDivStles } />
)
}
You can also describe style without creating style object like this:
<div style={{ color: "red", backgroundColor: "#fff" }} />
Be sure you are using double closure {{ }}.
EDIT
With :hover selector
You have two prosibilites. First you can use component state to determinate if component is hovered and then prepare correct style, e.g:
class Component extends React.Component {
constructor(props) {
super(props)
this.state = {
hovered: false
}
this.toggleHover = this.toggleHover.bind(this)
}
toggleHover(state) {
this.setState({
hovered: state
})
}
render() {
const styles = {
color: this.state.hovered ? "red" : "blue"
}
return (
<div style={styles} onMouseEnter={ () => this.toggleHover( true ) } onMouseLeave={ () => this.toggleHover( false ) }>
Text
</div>
);
}
}
Second you can use js styled components syntax and refer to other component, you can read more about this here: https://styled-components.com/docs/advanced#referring-to-other-components
But to be honest when I dealing with :hover or other selectors I prefer using default css files or much more often scss files prepared for components. So when I have e.g Button component in same location I have Button.css ( or Button.scss ) file where I can work with standard css. After this I have css files connected with components which should handled them.
Related
I am trying to override the styling applied by Material-UI's <Select> component when variant="outlined". For this example, I want the <Select>'s dropdown icon to be hidden and padding-right to be 0px.
From my understanding of the API, I should be able to overwrite the styles by passing in classes={{ icon: classes.hideIcon, outlined: classes.noPaddingRight }}, where classes is:
const useStyles = makeStyles(theme => ({
hideIcon: {
display: "none"
},
noPaddingRight: {
paddingRight: "0px"
}
}));
const classes = useStyles();
I am able to successfully hide the icon, but my noPaddingRight class is overridden by both MuiSelect-select.MuiSelect-select and MuiSelect-outlined.MuiSelect-outlined (I'm also confused what the . is doing in those two classes):
The only way I've gotten it to work is by using paddingRight: 0px !important but that's something I'd like to avoid if at all possible.
Here is the CodeSandbox: https://codesandbox.io/s/overwrite-select-style-zqk1r
You can use nesting selector for the className MuiSelect-outlined
hideIconPadding: {
"& .MuiSelect-outlined": {
paddingRight: "0px"
}
}
Notice that use className here:
className={classes.hideIconPadding}
I have a Playground here: https://codesandbox.io/s/736v9vjzw1
const Something = ({ classes, children, variant }) => {
return (
<div className={classes.someThing}>
<p> I'm some thing </p>
<SomeOtherThing />
<SomeOtherThing> I have some children </SomeOtherThing>
<SomeOtherThing> I have some children </SomeOtherThing>
<SomeOtherThing> I have some children </SomeOtherThing>
</div>
);
};
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30,
"& $someOtherThing": {
backgroundColor: "pink" // Doesn't work
},
"& p": {
fontWeight: "bold" //This works but is too broad
}
}
};
I have a situation here, where I want to style all the SomeOtherThings inside my SomeThing.
I can use & p selector to select the p element - but I don't like this. It would style any random ps I have around - and I don't want to have to look inside the component definition to find what it's top level element is.
How can I do this? Something like & SomeOtherElement.
The real world application of this, is that in some places I want have SomeOtherElement be displayed block and other places inline-block.
I would extend the SomeOtherThing component to accept a className and add it to the div if present. This will also work on a production setup, where the class names is minified to e.g. .t-0-root.
Here is a forked playground: https://codesandbox.io/s/zlzx277zzm which shows how to use it.
const SomeOtherThing = ({ classes, children, className }) => {
return (
<p className={`${classes.someOtherThing} ${className && className}`}>
I'm another thing {children}
</p>
);
};
I would most likely use the package classnames to conditionally render the class name instead of string interpolation.
const Something = ({ classes, children, variant }) => {
return (
<div className={classes.someThing}>
<p> I'm some thing </p>
<SomeOtherThing />
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
</div>
);
};
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30
},
someOtherThing: {
backgroundColor: "pink"
}
};
It's so simple, in your someThing CSS codes select the p elements with class someOtherThing class name and use not() CSS operation for p in top level, see following code:
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30,
"& [class*='SomeOtherThing']": {
backgroundColor: "pink" //
},
"& :not([class*='SomeOtherThing'])": {
fontWeight: "bold" // Just for top level p
}
}
};
and
const SomeOtherThing = ({ classes, children }) => {
return (
<p className={classes.root}> I'm another thing {children} </p>
);
};
CodeSandBox
The way that this works, is that by giving SomeOtherThing any jss class, it's going to render the dom element as something like:
<p class="SomeOtherThing-root-0-1-2"> I'm another thing I have some children </p>
which the [class*='SomeOtherThing'] attribute selector will match on.
You should note that this selector will apply to any deeper nested SomeOtherThings as well.
One problem with the "cascading" aspect of CSS is that it sort of breaks React's component model. But in React you can always create a wrapper or higher-order component that returns another with some predefined props, kind of like a factory function:
const Something = props => {
return (
<div className={props.className}>
// ...
</div>
)
}
const SomethingInline = props => {
return <Something className='display-inline' {...props} />
}
const SomethingBlock = props => {
return <Something className='display-block' {...props} />
}
const App = () => {
return (
<div>
<SomethingInline />
<SomethingBlock />
<SomethingBlock> I have children </SomethingBlock>
</div>
)
}
Instead of using the & selector to define your style, create a class that only applies to these specific versions of your component. In this way, the global scope of CSS is avoided and you can create these sort of declarative components that describe their own style, but don't require you to explicitly pass a class name.
I am new to react native and was creating my first.
In my add I decided to change the backgroundColor of my App dynamically for which I did something like this
let style = StyleSheet.flatten({
upperRow: {
display: "flex",
flexDirection: "row",
marginBottom: 5,
backgroundColor: "white"
},
})
let {
upperRow
} = style
And then something like this in componentWillReceiveProps
componentWillReceiveProps(nextProps) {
if (this.props.coinPrice != nextProps.coinPrice ) {
if (this.props.coinPrice > nextProps.coinPrice) {
console.log("previous value is greater")
//change background color to red
upperRow["backgroundColor"] = "#ffe5e5"
console.log(upperRow)
//We
}
}
}
This is throwing following error
You attempted to set the key backgroundColor with the value
#ffe5e5 on an object that is meant to be immutable and has been
frozen.
Question: Can anyone tell me what is going wrong here?
Something you should know about Stylesheet:
When you do Stylesheet.flatten, it will flatten arrays of style objects one immutable style object.
When you do Stylesheet.create, it will generate an immutable style object.
But why does it have to be immutable?
Refer the documentation, in order to increase the performance, the immutability of the style object will enable a simpler communication between the UI and JS Thread. In other words, they will just use the IDs of the style objects to communicate with each other through the native bridge. So, the object can't be mutated.
The solution to this problem is just as simple as this:
Using an array of styles.
Updating the styles dynamically using state.
Below is the code demonstrating how to do it:
class App extends React.Component {
state = {
clicked: false
}
handleOnPress = () => {
this.setState(prevState => ({clicked: !prevState.clicked}))
}
render() {
return (
<View style={[styles.container, {backgroundColor: this.state.clicked ? "blue" : "red"}]}>
<Button onPress={this.handleOnPress} title="click me" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
Here is the Snack Expo link of the code: https://snack.expo.io/SJBLS-1I7
So essentially I have a React component <Bore />. And I have an array of Bores and I need to style the first and last element of the array. I know how to access these elements with Bores[0] and Bores[Bores.length-1]. But my problem is figuring out how to style these specific components after creation. Would I have to do something like className += "newClass". I'm only 2 days into using React so any help would be greatly appreciated.
You can use style objects instead of mutating the class list. The important thing to remember is that CSS properties are camel case. Something like
class Parent extends Component {
constructor(props){
super(props);
this.state = {
style: {
backgroundColor: "green",
marginRight: "10px"
}
}
}
changeStyle = () => {
this.setState(() => {
return {
style: {
marginLeft: "10px",
backgroundColor: "red"
}
}
})
}
render = () => {
return (
<div>
<Child style={this.state.style} changeStyle={this.changeStyle}
</div>
)
}
}
const Child = ({ style, changeStyle }) => {
return (
<div style={style} onClick={changeStyle}>
<h1>Dummy</h1>
</div>
)
}
https://jsfiddle.net/rfhmxts2/ see here, click on the div to change it's background color and margins
It would be really helpful if we could compose multiple Cx components into one functional component that accepts multiple parameters as JSX attributes and can have its own nested (child) components.
<LoadingOverlay loading={bind('$page.loading')} >
<Grid />
</LoadingOverlay/>
When creating a custom Cx component, normally we need to create a class that extends some of the base components and implements certain predefined methods, which adds complexity to the process.
Here is one possible implementation of LoadingOverlay:
class LoadingOverlay extends PureContainer {
declareData() {
super.declareData(...arguments, {
loading: undefined
});
}
render (context, instance, key) {
let {data} = instance;
return <div key={key} className="cxb-loading-overlay-container">
{this.renderChildren(context, instance)}
{data.loading && <div className="cxe-loading-overlay">
<div className="cxe-loading-indicator">
{Icon.render('loading', {
style: {
width: '24px',
height: '24px',
position: 'relative',
top: '6px'
}
})
}
Loading...
</div>
</div>}
</div>;
}
}
For the example above, LoadingOverlay had to inherit from PureContainer and implement declareData and render methods.
And I would like to be able to use something simmilar to React's stateless functional components, like this:
const LoadingOverlay = (props) => {
return <div className="cxb-loading-overlay-container">
{props.children}
{data.loading && <div className="cxe-loading-overlay">
<div className="cxe-loading-indicator">
{Icon.render('loading', {
style: {
width: '24px',
height: '24px',
position: 'relative',
top: '6px'
}
})
}
Loading...
</div>
</div>}
</div>;
}
Is this possible in CxJS?
CxJS allows mixing React components with CxJS components, so your second example should work, except that you should use props.loading instead of data.loading.
React components can be defined as functional stateless components, or as ES6 classes extending the base React.Component class (or VDOM.Component in CxJS).
CxJS recently got support for CxJS functional components, and that would probably be the best choice for this example:
const LoadingOverlay = ({ loading, children }) => (
<cx>
<div className="cxb-loading-overlay-container">
{children}
<div className="cxe-loading-overlay" visible={loading}>
<div className="cxe-loading-indicator" ws>
<Icon
name="loading"
style="width:24px;height:24px;position:relative;top:6px"
/>
Loading...
</div>
</div>
</div>;
</cx>
);