I've got things working well with React-JSS: https://cssinjs.org/react-jss
The CSS styles are stored in an external file, styles.js. A classes object is then instantiated in the top-level component like this:
import injectSheet from 'react-jss';
import styleSheet from './styles.js';
class UserMgmtPage extends React.Component {
constructor(props) {
super(props);
}
render() {
const { classes } = this.props;
return (
<UsersProvider>
<AddUsers classes={classes} />
</UsersProvider>
</div>
);
}
}
const styledComponent = injectSheet(styleSheet)(UserMgmtPage);
const mapStateToProps = (state) => ({
session: state.session,
});
export default connect(mapStateToProps)(styledComponent);
The "problem" is that classes needs to be passed down from component to sub-component to sub-sub-component through prop drilling. I would like to avoid doing this and instead independently utilize classes in each sub-component that needs it - kind of like the way a React Context can be imported into any component, avoiding prop drilling.
I've tried several things but none work. Might anyone know of an approach that would work to accomplish this?
Related
I have created a simple datepicker component based on react-dates and implemented as per documentation at https://github.com/airbnb/react-dates
The datepicker seems to be working however the calendar styling is completely broken when clicking on the datepicker field
The datepicker code:
import React, { Component } from 'react';
import moment from 'moment';
import 'react-dates/initialize';
import { SingleDatePicker } from 'react-dates';
import 'react-dates/lib/css/_datepicker.css';
export default class DatePicker extends Component {
constructor(props) {
super(props);
this.state = {
selectedStartDate: moment(),
calendarSelectedStartDate: false
}
}
onDateChange = (selectedStartDate) => {
this.setState(() => ({ selectedStartDate }));
};
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarSelectedStartDate: focused }));
};
render() {
return (
<SingleDatePicker
date={this.state.selectedStartDate}
onDateChange={this.onDateChange}
focused={this.state.calendarSelectedStartDate}
onFocusChange={this.onFocusChange}
numberOfMonths={1}
isOutsideRange={() => false}
/>
)
}
}
Implementation is just call to :
<DatePicker />
outside of any parent html tags that could affect it.
The styling looks like this:
Ok i found an answer for this problem, so:
Are you trying to render the calendar inside another element that is not always visible, right?
Well, if you are doing that, in the parent component you must have an state like "isOpen" or something like that. Then, when you call the Picker component, must be like:
{isOpen && <DatePicker />}
I spent like two hours searching this solution. I hope that make sense for you.
import {createStyles, WithStyles} from "#material-ui/core";
const styles = (theme: Theme) => createStyles({
root: {}
});
interface MyProps extends WithStyles<typeof styles> {
}
export class MyComponent extends Component<MyProps> {
constructor(props: MyProps) {
super(props);
console.log(props.classes); // why this is undefined?
}
}
Why props.classes is undefined?
You can send props to component like where you calling
<MyComponent classes={.. Any thing you want to pass here ...} />
Finally got it working by "decorating" my class like this
export const MyComponent = withStyles(styles)(
class extends Component<MyProps> {
...
}
)
Then you can use the styles like this
<div className={this.props.classes.root}>
Hi I am building one next js app
I have build component components/search_location.js
constructor(props) {
super(props);
this.state = {locations: props.locations};
}
export default function SearchLocation({locations}){
return(
<div>
<h1></h1>
</div>
)
}
But with above code I am getting error saying
SyntaxError: /Users/search_project/components/search-location.js: Unexpected token, expected ";" (4:17)
export default function SearchLocation({locations}){
constructor(){
^
this.state = {
data: 'www.javatpoint.com'
}
I want to set state and then onclick of some button I want to change state as well, Can someone please suggest me how to do this?
You have a syntax error, constructor is something that is available only in javascript classes.
You should change your exported component from functional component to class component.
It should looks like this:
import React from 'react';
export default class extends React.Component {
constructor() {
this.state = {
data: 'www.javatpoint.com',
};
}
render() {
return <div>Content here</div>;
}
}
Consider a component that renders a button and says this button should have a red background and a yellow text color. Also there exists a Parent component that uses this child but says, the yellow color is fine, but I want the background color to be green.
withStyles
No problem using the old withStyles.
import React from "react";
import { withStyles } from "#material-ui/core/styles";
import { Button } from "#material-ui/core";
const parentStyles = {
root: {
background: "green"
}
};
const childStyles = {
root: {
background: "red"
},
label: {
color: "yellow"
}
};
const ChildWithStyles = withStyles(childStyles)(({ classes }) => {
return <Button classes={classes}>Button in Child withStyles</Button>;
});
const ParentWithStyles = withStyles(parentStyles)(({ classes }) => {
return <ChildWithStyles classes={classes} />;
});
export default ParentWithStyles;
https://codesandbox.io/s/passing-classes-using-withstyles-w17xs?file=/demo.tsx
makeStyles/useStyles
Let's try the makeStyles/useStyles instead and follow the guide Overriding styles - classes prop on material-ui.com.
import React from "react";
import { makeStyles } from "#material-ui/styles";
import { Button } from "#material-ui/core";
const parentStyles = {
root: {
background: "green"
}
};
const childStyles = {
root: {
background: "red"
},
label: {
color: "yellow"
}
};
// useStyles variant does NOT let me override classes
const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);
const ChildUseStyles = ({ classes: classesOverride }) => {
const classes = useChildStyles({ classes: classesOverride });
return (
<>
<Button classes={classes}>Button1 in Child useStyles</Button>
<Button classes={classesOverride}>Button2 in Child useStyles</Button>
</>
);
};
const AnotherChildUseStyles = props => {
const classes = useChildStyles(props);
return (
<>
<Button classes={classes}>Button3 in Child useStyles</Button>
</>
);
};
const ParentUseStyles = () => {
const classes = useParentStyles();
return <>
<ChildUseStyles classes={classes} />
<AnotherChildUseStyles classes={classes} />
</>
};
export default ParentUseStyles;
https://codesandbox.io/s/passing-classes-using-usestyles-6x5hf?file=/demo.tsx
There seems no way to get the desired effect that I got using withStyles. A few questions, considering I still want the same effect (green button yellow text) using some method of classes overriding (which seemed to make sense to me before).
How is my understanding wrong about how to pass classes as means to override parts of them using useStyles?
How should I approach it alternatively?
And if I'm using the wrong approach, why is material-ui still giving me a warning when the parent has something in the styles that the child doesn't have?
the key something provided to the classes prop is not implemented in [Child]
Is the migration from the old approach (withStyles) vs the new approach documented somewhere?
Btw, I'm aware of this solution but that seems cumbersome when you have too much you want to override.
const useStyles = makeStyles({
root: {
backgroundColor: 'red',
color: props => props.color, // <-- this
},
});
function MyComponent(props) {
const classes = useStyles(props);
return <div className={classes.root} />;
}
withStyles has very little functionality in it. It is almost solely a wrapper to provide an HOC interface to makeStyles / useStyles. So all of the functionality from withStyles is still available with makeStyles.
The reason you aren't getting the desired effect is simply because of order of execution.
Instead of:
const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);
you should have:
const useChildStyles = makeStyles(childStyles);
const useParentStyles = makeStyles(parentStyles);
The order in which makeStyles is called determines the order of the corresponding style sheets in the <head> and when specificity is otherwise the same, that order determines which styles win (later styles win over earlier styles). It is harder to get that order wrong using withStyles since the wrapper that you are using to override something else will generally be defined after the thing it wraps. With multiple calls to makeStyles it is easier to do an arbitrary order that doesn't necessarily put the overrides after the base styles they should impact.
The key to understanding this is to recognize that you aren't really passing in overrides, but rather a set of classes to be merged with the new classes. If childClasses.root === 'child_root_1' and parentClasses.root === 'parent_root_1', then the merged result is mergedClasses.root === 'child_root_1 parent_root_1' meaning any elements that have their className set to mergedClasses.root are receiving both CSS classes. The end result (as far as what overrides what) is fully determined by CSS specificity of the styles in the two classes.
Related answers:
Material UI v4 makeStyles exported from a single file doesn't retain the styles on refresh
Internal implementation of "makeStyles" in React Material-UI?
In Material-ui 4.11.x while creating styles using makeStyles wrap the enclosing styles with createStyles, and this style will have highest priority than the default one.
const useStyles = makeStyles((theme: Theme) =>
createStyles({
backdrop: {
zIndex: theme.zIndex.drawer + 1,
color: '#fff',
},
}),
);
You could try removing the createStyles and see the difference.
code source from https://material-ui.com/components/backdrop/
One way to achieve this using withStyles is the following and can be helpful to override css classes.
Supposing that you want to override a class called ".myclass" which contains "position: absolute;":
import { withStyles } from '#material-ui/styles';
const styles = {
"#global": {
".myClass": {
position: "relative",
}
}
};
const TestComponent = (props) => (
<>
<SomeComponent {...props}>
</>
);
export default withStyles(styles)(TestComponent);
After doing this, you override the definition of .myClass defined on <SomeComponent/> to be "position: relative;".
I'm a noob and I'm trying to compile a JSX following this tutorial :
http://xabikos.com/2015/03/18/Using-Reactjs-net-in-Web-Forms/
using reactjs.net
I'm trying to define a class like this...
class First extends React.createClass {
render(){
}
constructor(props) {
}
componentDidMount() {
}
}
Render method seems to work fine, but componentDidMount is not called,
and the constructor is also never called, any idea why is this happening?
You Are mixing The concept of function based components and class-based components, You can not use createClass while using class-based Components, That's why you are not getting what you desire.
The right way to make a component using class is this:-
import React from 'react';
class First extends React.Component{
constructor(props) {
super(props);
}
componentDidMount() {
}
render(){
}
}
And When You have to make components Using plain functions You have to use this:-
var First = React.createClass({
render:function(){
//Your view
}
})
I Hope it will solve your problem