how to automatically change contentStyle when the screen is responsive? - reactjs

I am using Material UI to make a application Layout. To make my layout responsive i use import ResponsiveMixin from 'react-responsive-mixin';
the ResponsiveMixin's doc doesn't provide me React.Component classes as example, so i try to use this import reactMixin from 'react-mixin'; instead.
here my code:
import
import React from 'react';
import reactMixin from 'react-mixin';
import ResponsiveMixin from 'react-responsive-mixin';
import Paper from 'material-ui/lib/paper';
contentStyle
const contentStyle = {
small: {
height: '100%',
width: '98%',
paddingTop: 60,
marginLeft: '1%',
paddingLeft: 0,
paddingRight: 0
},
medium: {
height: '100%',
width: '90%',
paddingTop: 60,
marginLeft: '5%',
paddingLeft: 0,
paddingRight: 0
},
large: {
height: '100%',
width: '80%',
paddingTop: 60,
marginLeft: 280,
paddingLeft: 40,
paddingRight: 40
}
};
this is my component
export class MainLayout extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.media({maxWidth: 600}, function () {
/*small*/
}.bind(this));
this.media({minWidth: 601, maxWidth: 1024}, function () {
/*medium*/
}.bind(this));
this.media({minWidth: 1025}, function () {
/*large*/
}.bind(this));
}
render() {
const {header, content, footer} = this.props; // destructure this.props to consts
return (
<div>
<header>
{header}
</header>
<main>
<Paper style={contentStyle} zDepth={1}>
{content}
</Paper>
</main>
<footer>
<Paper style={contentStyle}>
{footer}
</Paper>
</footer>
</div>
)
}
}
reactMixin(MainLayout.prototype, ResponsiveMixin);
ResponsiveMixin is located above
componentDidMount(){/contain responsiveMixin Function/}
Thanks for your help :D

Material UI favors inline styles (with its nice theming) so if you want to do it that way, you do it like this:
import React from 'react'
import {Mixins} from 'material-ui'
const {StylePropable, StyleResizable} = Mixins
export default React.createClass({
// Boilerplate and React lifecycle methods
propTypes: {
onChangeMuiTheme: React.PropTypes.func,
},
contextTypes: {
muiTheme: React.PropTypes.object,
},
mixins: [StylePropable, StyleResizable],
getInitialState() {
return {
}
},
// Helpers
getStyles() {
let styles = {
text: {
fontSize: 12,
color: this.context.muiTheme.rawTheme.palette.primary1Color
}
}
// example of a screen-size sensitive style
if (this.isDeviceSize(StyleResizable.statics.Sizes.MEDIUM)) { // active for >= MEDIUM
styles.text.fontSize = 20
}
return styles
},
render() {
let styles = this.getStyles()
return (
<p style={styles.text}>Hello world!</p>
)
}
})

Related

How to apply multiple classes to components on React 5?

Before v5, I was able to apply multiple class to the component like the following:
import React from "react";
import { makeStyles } from '#mui/styles';
const useStyles = makeStyles({
image: {
borderRadius: "50%",
width: 256,
height: 256,
},
shadow: {
boxShadow: "-4px -3px 45px 21px rgba(0,0,0,0.35)",
},
}));
const MyComponent = (props) => {
const { data } = props;
const classes = useStyles();
return (
<img src={data.image} className={`${classes.image} ${classes.shadow}`} alt={data.title} />
);
};
export default MyComponent;
However, since the change of styling engine(?), it seems like I can only apply a single styling like:
import React from "react";
import { styled } from "#mui/system";
const ProfileImage = styled("img")({
borderRadius: "50%",
width: 256,
height: 256,
});
const MyComponent= (props) => {
const { data } = props;
return (
<ProfileImage src={data.image} alt={data.title} />
);
};
export default MyComponent;
Would there be any possible solution to achieve the same behavior as the one above?
Thank you!
You could use an object and just spread the properties you want to use
const classes = {
image: {
borderRadius: "50%",
width: 256,
height: 256
},
shadow: {
boxShadow: "-4px -3px 45px 21px rgba(0,0,0,0.35)"
}
};
const ProfileImage1 = styled("img")({
...classes.image,
...classes.shadow
});
If you are using JS and want to benefit from type intellisense, you could use type annotation to get the hint of CSS properties
import { styled, SxProps, Theme } from "#mui/system";
/** #type{Record<string, SxProps<Theme>>} */
const classes = {
image: {
borderRadius: "50%",
width: 256,
height: 256
},
shadow: {
boxShadow: "-4px -3px 45px 21px rgba(0,0,0,0.35)"
}
};
Also, if you want to make the class conditional, styled component allows you to use prop from the component
const ProfileImage1 = styled("img")(({ shadow }) => ({
...classes.image,
...(shadow ? classes.shadow : {})
}));
export default function App() {
return (
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
gap: 5
}}
>
<ProfileImage1 src={"https://via.placeholder.com/256"} shadow />
<ProfileImage1 src={"https://via.placeholder.com/256"} />
</Box>
);
}

Initialize react hook in a class based component

I am trying to change the function-based component to the class-based component. I am getting an error while converting. How to initialize hook in a class component.
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
This is the error I am getting
Papebase Material UI
import React from 'react';
import PropTypes from 'prop-types';
import { createMuiTheme, ThemeProvider, withStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import Hidden from '#material-ui/core/Hidden';
import Typography from '#material-ui/core/Typography';
import Link from '#material-ui/core/Link';
import Navigator from '../Components/Navigator';
import Content from './Content';
import Header from '../Components/Header';
import { Switch, Route, BrowserRouter, Link as RouteLink } from "react-router-dom";
import { connect } from 'react-redux';
import { logout } from '../actions/auth';
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Podo
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
let theme = createMuiTheme({
palette: {
primary: {
light: '#63ccff',
main: '#009be5',
dark: '#006db3',
},
},
typography: {
h5: {
fontWeight: 500,
fontSize: 26,
letterSpacing: 0.5,
},
},
shape: {
borderRadius: 8,
},
props: {
MuiTab: {
disableRipple: true,
},
},
mixins: {
toolbar: {
minHeight: 48,
},
},
});
theme = {
...theme,
overrides: {
MuiDrawer: {
paper: {
backgroundColor: '#18202c',
},
},
MuiButton: {
label: {
textTransform: 'none',
},
contained: {
boxShadow: 'none',
'&:active': {
boxShadow: 'none',
},
},
},
MuiTabs: {
root: {
marginLeft: theme.spacing(1),
},
indicator: {
height: 3,
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
backgroundColor: theme.palette.common.white,
},
},
MuiTab: {
root: {
textTransform: 'none',
margin: '0 16px',
minWidth: 0,
padding: 0,
[theme.breakpoints.up('md')]: {
padding: 0,
minWidth: 0,
},
},
},
MuiIconButton: {
root: {
padding: theme.spacing(1),
},
},
MuiTooltip: {
tooltip: {
borderRadius: 4,
},
},
MuiDivider: {
root: {
backgroundColor: '#404854',
},
},
MuiListItemText: {
primary: {
fontWeight: theme.typography.fontWeightMedium,
},
},
MuiListItemIcon: {
root: {
color: 'inherit',
marginRight: 0,
'& svg': {
fontSize: 20,
},
},
},
MuiAvatar: {
root: {
width: 32,
height: 32,
},
},
},
};
const drawerWidth = 256;
const styles = {
root: {
display: 'flex',
minHeight: '100vh',
},
drawer: {
[theme.breakpoints.up('sm')]: {
width: drawerWidth,
flexShrink: 0,
},
},
app: {
flex: 1,
display: 'flex',
flexDirection: 'column',
},
main: {
flex: 1,
padding: theme.spacing(6, 4),
background: '#eaeff1',
},
footer: {
padding: theme.spacing(2),
background: '#eaeff1',
},
};
export class Paperbase extends React.Component {
render() {
const { classes } = this.props;
const [mobileOpen, setMobileOpen] = React.useState(false);
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
<div className={classes.root}>
<CssBaseline />
<nav className={classes.drawer}>
<Hidden smUp implementation="js">
<Navigator
PaperProps={{ style: { width: drawerWidth } }}
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
/>
</Hidden>
<Hidden xsDown implementation="css">
<Navigator PaperProps={{ style: { width: drawerWidth } }} />
</Hidden>
</nav>
<div className={classes.app}>
<Header onDrawerToggle={handleDrawerToggle} />
<main className={classes.main}>
<Switch>
<Route exact path="/dashboard/auth" render={() => <Content /> } />
<Route path="/Inbox" render={() => <div> Page inbox</div>} />
<Route path="/Starred" render={() => <div>PSage starred</div>} />
</Switch>
</main>
<footer className={classes.footer}>
<Copyright />
</footer>
</div>
</div>
</ThemeProvider>
</BrowserRouter>
)
}
}
Paperbase.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Paperbase);
Short answer you can't use react hooks on class based components.
Slightly longer answer:
Hooks were introduced to allow use of state in function components. If you're using a class component, then the mechanisms to manipulate state are built into the default class component behavior.
So in your example, you'd want to do something like:
Replace your state hook:
const [mobileOpen, setMobileOpen] = React.useState(false);
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
with a stateful class component and setState():
class PaperBase extends React.Component {
constructor(props){
super(props);
this.state = {
mobileOpen: true,
}
this.handleDrawerToggle = this.handleDrawerToggle.bind(this);
}
handleDrawerToggle = () => {
let mobileOpen = this.state.mobileOpen;
mobileOpen != mobileOpen;
this.setState = {
mobileOpen: mobileOpen,
}
}
// ...
}
Rather than explain how it all works here, I'll suggest reading the official tutorial on state in components: https://reactjs.org/docs/state-and-lifecycle.html

cant find variable props

I am trying to show the detail view when user taps on one of the list item. When the user taps on the listitem, I get an error saying Undefined is not an object
evaluating 'this.props.services.ser. Below is the screen shot of the error:
My list item page code is below:
import React, { Component } from 'react';
import { Text, View, StyleSheet, ListView } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux'
import reducers from '../reducers/ServiceReducer';
import ServiceItem from './ServiceItem';
import Icon from 'react-native-vector-icons/EvilIcons';
import ServiceDetail from './ServiceDetail';
const styles = StyleSheet.create({
container: {
flex: 1,
width: 353,
flexWrap: 'wrap',
paddingTop: 20,
paddingLeft: 20,
},
});
const store = createStore(reducers);
class AutoCompActivity extends Component {
renderInitialView() {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
});
this.dataSource = ds.cloneWithRows(this.props.services);
if (this.props.detailView === true) {
return (
<ServiceDetail />
);
} else {
return (
<ListView
enableEmptySections={true}
dataSource={this.dataSource}
renderRow={(rowData) =>
<ServiceItem services={rowData} />
}
/>
);
}
}
render() {
return (
<View style={styles.container}>
{this.renderInitialView()}
</View>
);
}
}
const mapStateToProps = state => {
return {
services: state.services,
detailView: state.detailView,
};
};
const ConnectedAutoCompActivity = connect(mapStateToProps)(AutoCompActivity);
const app1 = () => (
<Provider store={store}>
<ConnectedAutoCompActivity />
</Provider>
)
export default app1;
Each item that I display to the user is defined in js class serviceItem.js. Below is the code for serviceItem.js. I put the entire code inside TouchableWithoutFeedback. This is when I am getting an error when user taps on one of the listItem. I looked at this code several times, but could not figure out where I am doing wrong
import React from 'react';
import { Text, View, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';
import { connect } from 'react-redux';
import { getTheme } from 'react-native-material-kit';
import Icon from 'react-native-vector-icons/EvilIcons';
import * as actions from '../actions';
const theme = getTheme();
const styles = StyleSheet.create({
card: {
marginTop: 20,
},
title: {
top: 20,
left: 80,
fontSize: 24,
},
image: {
height: 100,
},
action: {
backgroundColor: 'black',
color: 'white',
},
icon: {
position: 'absolute',
top: 15,
left: 0,
color: 'white',
backgroundColor: 'rgba(255,255,255,0)',
},
});
const ServiceItem = (props) => {
return (
<TouchableWithoutFeedback
onPress={() => props.selectServices(props.services)}
>
<View style={[theme.cardStyle, styles.card]}>
<Text >{props.services.ser} </Text>
</View>
</TouchableWithoutFeedback>
);
};
const mapStateToProps = state => {
return {
selectServices: state.selectServices,
services: state.services
};
};
export default connect(mapStateToProps, actions)(ServiceItem);
When the user taps on each listitem. I am calling the class ServiceDetail.js. Below is the code for serviceDetail.js class:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import { Text, View, StyleSheet, Image, ScrollView, TouchableOpacity, Linking } from 'react-native';
import { connect } from 'react-redux';
import { getTheme } from 'react-native-material-kit';
import EvilIcon from 'react-native-vector-icons/EvilIcons';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import SimpleIcon from 'react-native-vector-icons/SimpleLineIcons';
import * as actions from '../actions';
const theme = getTheme();
const styles = StyleSheet.create({
card: {
marginTop: 10,
paddingBottom: 20,
marginBottom: 20,
borderColor: 'lightgrey',
borderWidth: 0.5,
},
title1: {
top: 10,
left: 80,
fontSize: 24,
},
title2: {
top: 35,
left: 82,
fontSize: 18,
},
image: {
flex: 0,
height: 100,
width: 333,
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
},
closeIcon: {
position: 'absolute',
top: 5,
left: 295,
color: 'rgba(233,166,154,0.8)',
backgroundColor: 'rgba(255,255,255,0)',
},
icon: {
position: 'absolute',
top: 15,
left: 0,
color: 'white',
backgroundColor: 'rgba(255,255,255,0)',
},
textArea: {
flexDirection: 'row',
paddingLeft: 20,
paddingTop: 10,
width: 260,
},
textIcons: {
color: '#26a69a',
},
actionArea: {
paddingTop: 10,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
},
});
class ServiceDetail extends Component {
handleClick = (link) => {
Linking.canOpenURL(link).then(suppported => {
if (supported) {
Linking.openURL(link);
} else {
console.log('Don\'t know how to open URI: ' + link);
}
});
};
render() {
return (
<ScrollView showsVerticalScrollIndicator={false}>
<View style={[theme.cardStyle, styles.card]}>
<Image
source={require('../images/background.jpg')}
style={[theme.cardImageStyle, styles.image]}
/>
<EvilIcon name={'user'} size={100} style={styles.icon}/>
<SimpleIcon name={'close'} size={30} style={styles.closeIcon}
onPress={() => this.props.noneSelected()} />
<Text style={[theme.cardTitleStyle, styles.title1]}>{this.props.services.ser}</Text>
<Text style={[theme.cardTitleStyle, styles.title2]}>from {this.props.services.Location}</Text>
<Text style={[theme.cardTitleStyle, styles.title2]}>from {this.props.services.SecondLoc}</Text>
<View style={styles.textArea}>
<MaterialIcon name={'phone'} size={40} style={styles.textIcons}/>
<Text style={theme.cardContentStyle}>{this.props.services.Phone}</Text>
</View>
<View style={styles.textArea}>
<MaterialIcon name={'email'} size={40} style={styles.textIcons}/>
<Text style={theme.cardContentStyle}>{this.props.services.email}</Text>
</View>
<View style={styles.actionArea}>
<Text>Call</Text>
<Text>Email</Text>
</View>
</View>
</ScrollView>
);
}
}
const mapStateToProps = state => {
return {
service: state.serviceSelected,
};
};
export default connect(mapStateToProps, actions)(ServiceDetail);
My index.js class has the following code under actions folder:
export const selectServices = (serviceId) => {
return {
type: 'SELECTED_SERVICE',
payload: serviceId,
};
};
export const noneSelected = () => {
return {
type: 'NONE_SELECTED',
};
};
My serviceReducer has the following code:
import services from './services.json';
const initialState = {
services,
detailView: false,
serviceSelected: null,
};
export default (state = initialState, action) => {
switch (action.type) {
case 'SELECTED_SERVICE':
return {
...state,
detailView: true,
serviceSelected: action.payload
}
case 'NONE_SELECTED':
return {
...state,
detailView: false,
serviceSelected: null,
}
default:
return state;
}
}
I am developing this application on windows machine on android emulator. I know I am missing something. I looked at each and every line, but could not figure out what am I doing wrong. I am new to react native and trying to follow the example to make this app. I tried to debug the application using chrome, but keep getting an error that could not connect to remote debugging.
any help will be highly appreciated.
I see you pass props and use it to your const ServiceItem. You need to use mapStateToProps also then pass to your connect at serviceItem.js.
const mapStateToProps = state => {
return {
selectServices: state.selectServices,
services: state.services
};
};
export default connect(mapStateToProps, actions)(ServiceItem);
Your ServiceDetail.js also should be:
const mapStateToProps = state => {
return {
services: state.services
};
};
export default connect(mapStateToProps, actions)(ServiceDetail);
Your ServiceItem component is just a presentational component, in my opinion, it need not to be connected to redux store, instead, pass the data and event hook from parent to ServiceItem component and that will work just fine. That will solve your props problem as well.
Point made by "DennisFrea" still holds good. i am just suggesting another of achieving the same thing.

Child component won't render from function

I am trying to render a child component using the function renderHowManyAlcohol()
The component LYDSelectNumber doesn't render, the correct props are being passed down, any ideas why this doesn't render?
render() {
return (
<Flexible>
<LYDSceneContainer
goBack={this.props.goBack}
subSteps={this.props.subSteps}>
<Flexible>
{this.renderHowManyAlcohol()}
</Flexible>
</LYDSceneContainer>
</Flexible>
);
}
renderHowManyAlcohol() {
return (
<View style={styles.HowManyAlcoholContainer}>
<Text>this renders</Text>
// this component below doesn't
<LYDSelectNumber
selectedNumberValue={this.props.selectedNumberValue}
onChangeNumber={this.props.onChangeNumber}
/>
</View>
);
}
LYDSelectNumber component, styles.container shows as a number '60', which is weird, I have the styles at the bottom of the page.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Picker, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import * as theme from '../../../theme';
const Item = Picker.Item;
export const SelectedNumber = ({ value = 0, displayPicker = () => {} } = {}) =>
<TouchableOpacity onPress={displayPicker}>
<View style={styles.centerWrap}>
<View style={styles.selectedNumberWrap}>
<Text style={styles.selectedNumberText}>
{value}
</Text>
</View>
</View>
</TouchableOpacity>;
class LYDSelectNumber extends Component {
static propTypes = {
onChangeNumber: PropTypes.func.isRequired,
numbersRange: PropTypes.array,
style: PropTypes.any,
selectedNumberValue: PropTypes.number,
};
static defaultProps = {
numbersRange: [18, 120],
style: undefined,
selectedNumberValue: undefined,
};
render() {
return (
<View style={styles.container}>
<SelectedNumber value={this.props.selectedNumberValue} />
<Picker
style={styles.picker}
selectedValue={this.props.selectedNumberValue}
onValueChange={this.props.onChangeNumber}>
{this._renderNumbers()}
</Picker>
</View>
);
}
_renderNumbers = () => {
const [firstNumber, lastNumber] = this.props.numbersRange;
let numbersItems = [];
let n = firstNumber;
while (n <= lastNumber) {
numbersItems.push(<Item key={n} label={`${n}`} value={n} />);
n++;
}
return numbersItems;
};
}
export default LYDSelectNumber;
const styles = StyleSheet.create({
container: {
flex: 3,
justifyContent: 'center',
alignItems: 'center',
},
picker: {
position: 'absolute',
top: 0,
width: 1000,
height: 1000,
},
centerWrap: {
alignItems: 'center',
},
selectedNumberWrap: {
width: theme.utils.responsiveWidth(40),
paddingBottom: 20,
borderBottomWidth: 2,
alignItems: 'center',
borderBottomColor: theme.colors.darkGranate,
},
selectedNumberText: {
...theme.fontStyles.selectedNumber,
},
});

react-burger-menu css does not work

I'm using burger-menu and i can't set CSS for the burger menu like the author guide: https://github.com/negomi/react-burger-menu
Here's my burger menu component:
import React from 'react';
import BurgerMenu from 'react-burger-menu';
import { List, ListItem, ListItemContent } from 'react-mdl';
var MenuWrap = React.createClass({
getInitialState() {
return {hidden : false};
},
toggle() {
this.setState({hidden: !this.state.hidden});
},
render() {
let style;
if (this.state.hidden) {
style = {display: 'none'};
}
return (
<div style={style} className={this.props.side}>
{this.props.children}
</div>
);
}
});
export default class LeftSidebar extends React.Component {
constructor(props) {
super(props);
this.state = {
currentMenu: 'push',
side: 'left',
hidden: true,
};
};
render() {
const Menu = BurgerMenu[this.state.currentMenu];
var styles = {
bmBurgerButton: {
position: 'fixed',
width: '36px',
height: '30px',
left: '36px',
top: '36px'
},
bmBurgerBars: {
background: '#373a47'
},
bmCrossButton: {
height: '24px',
width: '24px'
},
bmCross: {
background: '#bdc3c7'
},
bmMenu: {
background: '#373a47',
padding: '2.5em 1.5em 0',
fontSize: '1.15em'
},
bmMorphShape: {
fill: '#373a47'
},
bmItemList: {
color: '#b8b7ad',
padding: '0.8em'
},
bmOverlay: {
background: 'rgba(0, 0, 0, 0.3)'
}
};
return (
<MenuWrap wait={20}>
<Menu
style={styles}
noOverlay id={this.state.currentMenu}
pageWrapId={'page-wrap'}
outerContainerId={'outer-container'}
>
{console.log(Menu)}
<List>
<ListItem>
<ListItemContent icon="person">Dashboard</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">Community</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">About</ListItemContent>
</ListItem>
</List>
</Menu>
</MenuWrap>
);
}
};
And here is my main component:
import React from 'react';
import styles from './Main.scss';
import LeftSidebar from '../LeftSidebar/LeftSidebar'
export default class Program extends React.Component {
render() {
return (
<div id="outer-container" style={{height: '100%'}}>
<LeftSidebar />
<div id="page-wrap">
<p>Content</p>
</div>
</div>
);
}
}
All of the css from variable styles does not work.
EDIT: the problem above is solved by change style ={styles} to styles = {styles}. The other problem is: when i click close, the sidebar menu shift down about 10 or 20px before moving back to the left. How to remove that shift down effect?
Seems like you have a typo. It should be styles={styles} instead of style={styles}.

Resources