I am trying to style some buttons based on whether they are 'active' or not, and also whether or not the use is hovering the mouse over them.
It works to some extent, however, it's behaving in a way that I don't fully understand.
How do I apply a conditional style to a component, based on its state, as well as based on user behavior?
I have an example in this SANDBOX
And the main JS file copied here:
demo.js
import React from "react";
import PropTypes from "prop-types";
//import { makeStyles } from "#material-ui/core/styles";
import { withStyles } from "#material-ui/styles";
import { Button } from "#material-ui/core";
const useStyles = theme => ({
root: {
backgroundColor: theme.palette.secondary.paper,
width: 500
},
pageButton: {
backgroundColor: "black",
color: "blue",
width: 30,
minWidth: 20,
"&:hover": {
backgroundColor: "green"
}
},
normalButton: {
width: 30,
minWidth: 20,
backgroundColour: "red"
}
});
class Feature extends React.Component {
constructor(props) {
super(props);
this.state = { currentPage: 0 };
}
handleClick(page) {
this.setState({ currentPage: page });
}
fetchPageNumbers() {
return [1, 2, 3];
}
render() {
const classes = this.props.classes;
return (
<div className={classes.root}>
{this.fetchPageNumbers().map((page, index) => {
return (
<div>
<Button
onClick={() => this.handleClick(page)}
key={page}
className={
this.state.currentPage === page
? classes.pageButton
: classes.normalbutton
}
>
{page}
</Button>
<Button
onClick={() => {}}
key={page * 20}
className={classes.normalButton}
>
{page * 20}
</Button>
</div>
);
})}
</div>
);
}
}
Feature.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(useStyles)(Feature);
There are two rows. The second row picks up the styles just fine.
The first row will only adhere when the button is clicked. I want to be able to set the state based on whether the current button is active (ie. state == buttonNumber), and also whether or not the user is hovering over any of the buttons.
How do I apply a conditional style to a component, based on its state, as well as based on user behavior?
For conditional style based on user behavior
I guess your current demand is when it's hovering.
"&:hover": {
// Hover styles
}
For conditional style based on params(props)
withStyles doesn't have access to the properties.
refer: issue: Can withStyles pass props to styles object? #8726
But there are multiple work-around solutions
1.use injectSheet HOC
notice that the useStyles in your code is actually not a hook
const styles = props => ({
root: {
width: props.size === 'big' ? '100px' : '20px'
}
})
or
const styles = {
root: {
width: props => props.size === 'big' ? '100px' : '20px'
}
}
with
const CustomFeature = ({size, classes}) => <Feature className={classes.root} />;
export default withStyles(styles)(CustomFeature);
2.use style hooks with params (for functional components)
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
width: props => props .size === "big" ? "100px" : "20px"
}
}));
const classes = useStyles();
or
import { makeStyles } from "#material-ui/core/styles";
const useStyles = params =>
makeStyles(theme => ({
root: {
width: params.size === "big" ? "100px" : "20px"
}
}));
const classes = useStyles(whateverParamsYouWant)();
In response to #keikai you can also pass in an object into the styles() hook (I was getting an error by just passing in props).
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
width: ({ size }) => (size === "big" ? "100px" : "20px")
}
}));
const classes = useStyles({ size });
Related
I have a file register.js with some UI component.
import CustomHeader from '../components/Header';
...
static navigationOptions = ({navigation, navigation: { state } }) => {
return {
title: '',
headerStyle: CustomHeader
}
};
I try to create and call CustomHeader style from another constant file.
import { getStatusBarHeight } from "react-native-safearea-height";
import { Platform } from 'react-native';
var iosMarginTop = getStatusBarHeight(true);
const headerStyle = ({backgroundColor = '#000'}) => {
backgroundColor: backgroundColor,
marginTop: Platform.OS == 'ios' ? iosMarginTop : 0
}
export default headerStyle;
How can i dynamically call customHeader style and pass some parameter for specific UI style for example backgroundColor? and by default, if none parameter passed, it will remain default value "#000"
Update your code like this,
const headerStyle = ({backgroundColor}) => {
backgroundColor: backgroundColor ? backgroundColor : "#000",
marginTop: Platform.OS == 'ios' ? iosMarginTop : 0
}
So I'm using react-visibility-sensor with react-spring to animate text sliding char by char from any side I want.
In my home page the animation is running smoothly, I use it twice one from the right side and another from the top side.
When I switch routes and go to another page the animation does not work.
I have my code divided in an "Title" component "Char" component and a custom hook "useAnimatedText".
Title component:
import React from "react";
import VisibilitySensor from "react-visibility-sensor";
import useAnimatedText from "../../hooks/useAnimatedText";
import Char from './Char'
const Title = ({title, side}) => {
// HERE I CALL A CUSTOM HOOK THAT WILL DIFINE IF THE ELEMENT IS VISIBLE OR NOT
// AND HANDLE THE ANIMATION WHEN NECESSARY
const [isVisible, onChange, objArray] = useAnimatedText(title)
let elements = objArray.map((item, i) => {
return(
<Char
key={i}
isVisible={isVisible}
item={item}
delay={400 + (i * 40)}
side={side}
/>
)
})
console.log(isVisible)
return(
<VisibilitySensor onChange={onChange} >
<span className="title-box">
<h1 className="my-heading divided-heading">
{elements}
</h1>
<hr className="title-ruller"></hr>
</span>
</VisibilitySensor>
)
}
export default Title
Char component:
import { useSpring, animated } from "react-spring"
const Char = (props) => {
const { isVisible, item, delay, isBouncy, side} = props
const [ref, addBounce] = useBounce()
let springConfig = {}
if (side === 'right') {
springConfig = {
to: {
opacity: isVisible ? 1 : 0,
translateX : isVisible ? '0px' : '1000px'
},
config: { mass:2, tension: 200, friction: 30},
delay: delay
}
}
else if (side === 'top') {
springConfig = {
to: {
opacity: isVisible ? 1 : 0,
translateY: isVisible ? '0px' : '-500px'
},
config:{ mass:2, tension: 250, friction: 35},
delay: delay
}
}
const spring = useSpring({...springConfig})
return(
<animated.span
style={ spring }
className={isVisible ? 'is-visible' : 'is-not-visible'}
>
{item.char === ' ' ? <span> </span> : item.char}
</animated.span>
)
}
export default Char
This is the custom Hook:
import { useState } from "react";
import { stringToArray } from '../helpers'
// HOOK THAT HANDLES THE TEXT ANIMATION BY SETTING A STATE OF VISIBILITY
function useAnimatedText(string) {
const [isVisible, setVisibility] = useState(false);
const onChange = visiblity => {
visiblity && setVisibility(visiblity);
};
let objArray = stringToArray(string)
return [isVisible, onChange, objArray]
}
export default useAnimatedText
I did a console.log(isVisible) and the value was true but it was rendering in the page the spring values as if it was false(not visible).
I really canĀ“t understand where I'm going wrong here, the only problem I have is when I'm not at my main route, could it be because of react-router-dom?
If someone has any clue, let me know.
I have an application with a table, the table has a checkbox to set a Tenant as Active, this variable is a global variable that affects what the user does in other screens of the application.
On the top right of the application, I have another component called ActiveTenant, which basically shows in which tenant the user is working at the moment.
The code of the table component is like this:
import React, { Component } from 'react';
import { Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.id,
TestSiteCollectionUrl: row.TestSiteCollectionUrl,
TenantName: row.TenantName,
Email: row.Email
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
const columns = [
{
title: 'TenantName',
dataIndex: 'TenantName',
key: 'TenantName',
},
{
title: 'TestSiteCollectionUrl',
dataIndex: 'TestSiteCollectionUrl',
key: 'TestSiteCollectionUrl',
},
{
title: 'Email',
dataIndex: 'Email',
key: 'Email',
}
];
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if(selectedRows[0].TenantName != undefined){
console.log(selectedRows[0].TenantName);
const options = {
method: 'post'
};
adalApiFetch(fetch, "/Tenant/SetTenantActive?TenantName="+selectedRows[0].TenantName.toString(), options)
.then(response =>{
if(response.status === 200){
Notification(
'success',
'Tenant set to active',
''
);
}else{
throw "error";
}
})
.catch(error => {
Notification(
'error',
'Tenant not activated',
error
);
console.error(error);
});
}
},
getCheckboxProps: record => ({
type: Radio
}),
};
return (
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
);
}
}
export default ListTenants;
And the code of the ActiveTenant component its also very simple
import React, { Component } from 'react';
import authAction from '../../redux/auth/actions';
import { adalApiFetch } from '../../adalConfig';
class ActiveTenant extends Component {
constructor(props) {
super(props);
this.state = {
tenant: ''
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant/GetActiveTenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
this.setState({ tenant: responseJson.TenantName });
}
})
.catch(error => {
this.setState({ tenant: '' });
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
return (
<div>You are using tenant: {this.state.tenant }</div>
);
}
}
export default ActiveTenant;
The problem is, if I have multiple tenants on my database registered and I set them to active, the server side action occurs, and the state is changed, however on the top right its still showing the old tenant as active, UNTIL I press F5 to refresh the browser.
How can I achieve this?
For the sake of complete understandment of my code I will need to paste below other components:
TopBar which contains the active tenant
import React, { Component } from "react";
import { connect } from "react-redux";import { Layout } from "antd";
import appActions from "../../redux/app/actions";
import TopbarUser from "./topbarUser";
import TopbarWrapper from "./topbar.style";
import ActiveTenant from "./activetenant";
import TopbarNotification from './topbarNotification';
const { Header } = Layout;
const { toggleCollapsed } = appActions;
class Topbar extends Component {
render() {
const { toggleCollapsed, url, customizedTheme, locale } = this.props;
const collapsed = this.props.collapsed && !this.props.openDrawer;
const styling = {
background: customizedTheme.backgroundColor,
position: 'fixed',
width: '100%',
height: 70
};
return (
<TopbarWrapper>
<Header
style={styling}
className={
collapsed ? "isomorphicTopbar collapsed" : "isomorphicTopbar"
}
>
<div className="isoLeft">
<button
className={
collapsed ? "triggerBtn menuCollapsed" : "triggerBtn menuOpen"
}
style={{ color: customizedTheme.textColor }}
onClick={toggleCollapsed}
/>
</div>
<ul className="isoRight">
<li
onClick={() => this.setState({ selectedItem: 'notification' })}
className="isoNotify"
>
<TopbarNotification locale={locale} />
</li>
<li>
<ActiveTenant />
</li>
<li
onClick={() => this.setState({ selectedItem: "user" })}
className="isoUser"
>
<TopbarUser />
<div>{ process.env.uiversion}</div>
</li>
</ul>
</Header>
</TopbarWrapper>
);
}
}
export default connect(
state => ({
...state.App.toJS(),
locale: state.LanguageSwitcher.toJS().language.locale,
customizedTheme: state.ThemeSwitcher.toJS().topbarTheme
}),
{ toggleCollapsed }
)(Topbar);
App.js which contains the top bar
import React, { Component } from "react";
import { connect } from "react-redux";
import { Layout, LocaleProvider } from "antd";
import { IntlProvider } from "react-intl";
import { Debounce } from "react-throttle";
import WindowResizeListener from "react-window-size-listener";
import { ThemeProvider } from "styled-components";
import authAction from "../../redux/auth/actions";
import appActions from "../../redux/app/actions";
import Sidebar from "../Sidebar/Sidebar";
import Topbar from "../Topbar/Topbar";
import AppRouter from "./AppRouter";
import { siteConfig } from "../../settings";
import themes from "../../settings/themes";
import { themeConfig } from "../../settings";
import AppHolder from "./commonStyle";
import "./global.css";
import { AppLocale } from "../../dashApp";
import ThemeSwitcher from "../../containers/ThemeSwitcher";
const { Content, Footer } = Layout;
const { logout } = authAction;
const { toggleAll } = appActions;
export class App extends Component {
render() {
const { url } = this.props.match;
const { locale, selectedTheme, height } = this.props;
const currentAppLocale = AppLocale[locale];
return (
<LocaleProvider locale={currentAppLocale.antd}>
<IntlProvider
locale={currentAppLocale.locale}
messages={currentAppLocale.messages}
>
<ThemeProvider theme={themes[themeConfig.theme]}>
<AppHolder>
<Layout style={{ height: "100vh" }}>
<Debounce time="1000" handler="onResize">
<WindowResizeListener
onResize={windowSize =>
this.props.toggleAll(
windowSize.windowWidth,
windowSize.windowHeight
)
}
/>
</Debounce>
<Topbar url={url} />
<Layout style={{ flexDirection: "row", overflowX: "hidden" }}>
<Sidebar url={url} />
<Layout
className="isoContentMainLayout"
style={{
height: height
}}
>
<Content
className="isomorphicContent"
style={{
padding: "70px 0 0",
flexShrink: "0",
background: "#f1f3f6",
position: "relative"
}}
>
<AppRouter url={url} />
</Content>
<Footer
style={{
background: "#ffffff",
textAlign: "center",
borderTop: "1px solid #ededed"
}}
>
{siteConfig.footerText}
</Footer>
</Layout>
</Layout>
<ThemeSwitcher />
</Layout>
</AppHolder>
</ThemeProvider>
</IntlProvider>
</LocaleProvider>
);
}
}
export default connect(
state => ({
auth: state.Auth,
locale: state.LanguageSwitcher.toJS().language.locale,
selectedTheme: state.ThemeSwitcher.toJS().changeThemes.themeName,
height: state.App.toJS().height
}),
{ logout, toggleAll }
)(App);
I think this should be enough to illustrate my question.
You're not using redux correctly there. You need to keep somewhere in your redux state your active tenant; That information will be your single source of truth and will be shared among your components throughout the app. Every component that will need that information will be connected to that part of the state and won't need to hold an internal state for that information.
Actions, are where you would call your API to get your active tenant information or set a new tenant as active. These actions wil call reducers that will change your redux state (That includes your active tenant information) and those redux state changes will update your app components.
You should probably take some time to read or re-read the redux doc, it's short and well explained !
I'm using redux for the first time and something subtle is getting by me.
I have a container called Dashboard that displays two SimpleTabs. A simple tab is component that gets pressed and returns a number to its container for the item pressed. I can see actions being dispatched, event handler firing etc but the state being received in mapStateToProps never contains the item values. This might be why the render is never getting fired because the state is not changed.
Note: I've used the Ignite boilerplate as a starting point. It makes use of reduxsauce so the DashboardRedux.js may look a little unusual.
Dashboard.js
import React, { Component } from 'react'
import { ScrollView, Text, View, Image, TouchableOpacity, StyleSheet } from 'react-native'
import moment from 'moment'
import { Images, Colors, Metrics, ApplicationStyles } from '../Themes'
import SimpleTab from '../Components/SimpleTab'
import DashboardHeader from '../Components/DashboardHeader'
import DashboardActions from '../Redux/DashboardRedux'
import { connect } from 'react-redux'
export class Dashboard extends Component {
//TODO make numbers into enums
constructor(props) {
super(props)
this.updateTimeframe = this.updateTimeframe.bind(this)
this.updateAnalysisView = this.updateAnalysisView.bind(this)
const curTimeframe = 0
const curAnalysisView = 0
this.state = {curTimeframe, curAnalysisView}
}
// Event handler for timeframe tab
updateTimeframe(newValue) {
//newValue gets received as expected
this.props.updateTimeframe(newValue)
}
// Event handler for analysisview tab
updateAnalysisView(newValue) {
this.props.updateAnalysisView(newValue)
}
getUpdateTime = () => {
let s = moment().format("h:mm a")
return s
}
// Takes us back to login
openLoginScreen = () => {
//TODO does navigater have notion of <back>?
this.props.navigation.navigate('LoginScreen')
}
// For info on flex: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
render () {
let styles = ApplicationStyles.screen
/*
let localStyles = StyleSheet.create({
container: {
paddingBottom: Metrics.baseMargin
},
centered: {
alignItems: 'center'
}
})
console.log(styles)
*/
return (
//Problem: this.props.curTimeframe is always undefined
<View style={styles.mainContainer}>
<DashboardHeader updateTime={this.getUpdateTime()}></DashboardHeader>
<View style={{justifyContent: 'space-between'}} >
<SimpleTab
onSelect={this.updateTimeframe}
curTab={this.props.curTimeframe}
tabNames={["TODAY", "1W", "1M", "3M", "6M"]}
/>
</View>
<View style={{flex:1}} >
<Text style={{color: Colors.snow}}>
Analytical stuff for {this.props.curTimeframe} and {this.props.curAnalysisView}
</Text>
</View>
<View style={{height:60, justifyContent: 'space-between'}} >
<SimpleTab
onSelect={this.updateAnalysisView}
curTab={this.props.curAnalysisView}
tabNames={["HOME", "DAYPART", "REC", "INGRED", "SETTINGS"]}
/>
</View>
</View>
)}
}
const mapStateToProps = (state) => {
// Problem: state passed never contains curAnalysisView or curTimeframe
return {
curAnalysisView: state.curAnalysisView,
curTimeframe: state.curTimeframe
}
}
const mapDispatchToProps = (dispatch) => {
return {
updateTimeframe: newValue => dispatch(DashboardActions.updateTimeframe(newValue)),
updateAnalysisView: newValue => dispatch(DashboardActions.updateAnalysisView(newValue))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
DashboardRedux.js
import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'
/* ------------- Types and Action Creators ------------- */
const { Types, Creators } = createActions({
updateTimeframe: ['newValue'],
updateAnalysisView: ['newValue'],
})
export default Creators
export const DashboardTypes = Types
/* ------------- Initial State ------------- */
export const INITIAL_STATE = Immutable({
curTimeframe: 0,
curAnalysisView: 0
})
/* ------------- Reducers ------------- */
export const updateTimeframe = (state, {newValue}) => {
//newValue gets passed as expected
return state.merge({curTimeframe: newValue});
}
export const updateAnalysisView = (state, {newValue}) => {
return state.merge({curAnalysisView: newValue});
}
/* ------------- Hookup Reducers To Types ------------- */
export const reducer = createReducer(INITIAL_STATE, {
[Types.UPDATE_TIMEFRAME]: updateTimeframe,
[Types.UPDATE_ANALYSIS_VIEW]: updateAnalysisView
})
SimpleTab.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { View, Text, Image, StyleSheet, TouchableHighlight } from 'react-native'
import { Colors, Metrics, Fonts, Images } from '../Themes/'
import styles from '../Themes/ApplicationStyles'
export default class SimpleTab extends Component {
static defaultProps = {
onSelect: null,
curTab: 0,
tabNames: ["Tab1", "Tab2", "Tab3"]
}
static propTypes = {
onSelect: PropTypes.func,
curTab: PropTypes.number,
tabNames: PropTypes.array
}
tabSelected = (tabNum) => {
this.props.onSelect(tabNum);
}
renderTabBar = () => {
let localStyles = StyleSheet.create({
unselectedText: {
marginTop: Metrics.baseMargin,
marginHorizontal: Metrics.baseMargin,
textAlign: 'center',
fontFamily: Fonts.type.base,
fontSize: Fonts.size.regular,
color: Colors.snow
},
selectedText: {
marginTop: Metrics.baseMargin,
marginHorizontal: Metrics.baseMargin,
textAlign: 'center',
fontFamily: Fonts.type.base,
fontSize: Fonts.size.regular,
fontWeight: 'bold',
color: Colors.fire
}
})
let result = []
for (i=0; i<this.props.tabNames.length; i++) {
let tabStyle = (i == this.props.curTab) ? localStyles.selectedText : localStyles.unselectedText
result.push(
<TouchableHighlight key={this.props.tabNames[i]} onPress={this.tabSelected.bind(this, i)}>
<Text style={tabStyle}>{this.props.tabNames[i]}</Text>
</TouchableHighlight>
)
}
return result
}
render () {
console.log("rendering tab")
return (
<View flexDirection='row' style={styles.contentContainer}>
{this.renderTabBar()}
</View>
)
}
}
MapStateToProps receives the new state properties via reducers. Your MapStatetoProps in Dashboard.js should look like below to get the new values.
const mapStateToProps = (state) => {
// Problem: state passed never contains curAnalysisView or curTimeframe
//new state values should be accessed via reducers..
return {
curAnalysisView: state.updateAnalysisView['curAnalysisView'],
curTimeframe: state.updateTimeframe['curTimeframe']
}
}
the mapStateToProps should like:
const mapStateToProps = (state) => {
const stateObj = state.toJS()
return {
curAnalysisView: stateObj.curAnalysisView,
curTimeframe: stateObj.curTimeframe
}
}
the .toJS() function converts it from immutable object to JS object.
Also, the reducer should have a default case that just returns the current state for when there is no action passed.
It turned out I needed to specify the "dashboard" branch of the state tree like this:
const mapStateToProps = (state) => {
return {
curAnalysisView: state.dashboard.curAnalysisView,
curTimeframe: state.dashboard.curTimeframe
}
}
I want to animate the depth of the whole Card when the mouse is over it.
I try this (so-so I'm new in React) but I have no idea how to do it:
<Card
linkButton={true}
href="/servicios/"
onClick={Link.handleClick} zDepth={3}
onMouseEnter={this.setState({zDepth={1}})}>
</Card>
Thanks in advance.
5 years later and there is still no correct answer, you do not have to set the component state when it hovers, just use the pseudo-class :hover:
<Card
sx={{
':hover': {
boxShadow: 20, // theme.shadows[20]
},
}}
>
If you want to use styled():
const options = {
shouldForwardProp: (prop) => prop !== 'hoverShadow',
};
const StyledCard = styled(
Card,
options,
)(({ theme, hoverShadow = 1 }) => ({
':hover': {
boxShadow: theme.shadows[hoverShadow],
},
}));
<StyledCard hoverShadow={10}>
<Content />
</StyledCard>
Live Demo
constructor(props) {
super(props);
this.state = { shadow: 1 }
}
onMouseOver = () => this.setState({ shadow: 3 });
onMouseOut = () => this.setState({ shadow: 1 });
<Card
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
zDepth={this.state.shadow}
>
Updated #1
Full example
// StyledCard.js
import React, { Component } from 'react';
import { Card } from 'material-ui/Card';
class StyledCard extends Component {
state: {
shadow: 1
}
onMouseOver = () => this.setState({ shadow: 3 });
onMouseOut = () => this.setState({ shadow: 1 });
render() {
return (
<Card
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
zDepth={this.state.shadow}
>
{this.props.children}
</Card>
);
}
export default StyledCard;
.
// Container.js
import React from 'react';
import StyledCard from './StyledCard';
const Container = () => [
<StyledCard>Card 1</StyledCard>,
<StyledCard>Card 2</StyledCard>,
<StyledCard>Card 3</StyledCard>,
];
export default Container;
UPDATED #2
With HOC
// withShadow.js
import React from 'react';
const withShadow = (Component, { init = 1, hovered = 3 }) => {
return class extends React.Component {
state: {
shadow: init
};
onMouseOver = () => this.setState({ shadow: hovered });
onMouseOut = () => this.setState({ shadow: init });
render() {
return (
<Component
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
zDepth={this.state.shadow}
{...this.props}
/>
);
}
};
};
export default withShadow;
.
// Container.js
import React from 'react';
import { Card } from 'material-ui/Card';
import withShadow from './withShadow';
const CardWithShadow = withShadow(Card, { init: 2, hovered: 4 });
const Container = () => [
<CardWithShadow>Card 1</CardWithShadow>,
<CardWithShadow>Card 2</CardWithShadow>,
<CardWithShadow>Card 3</CardWithShadow>,
];
export default Container;
#Alex Sandiiarov answer didnt work for me. The docs show to use the raised property.
https://material-ui.com/api/card/
class Component extends React.Component{
state = {
raised:false
}
toggleRaised = () => this.setState({raised:!this.state.raised});
render(){
return <Card onMouseOver={this.toggleRaised}
onMouseOut={this.toggleRaised}
raised={this.state.raised}>
...
</Card>
}
}