Skip to content

Instantly share code, notes, and snippets.

@ivawzh
Last active April 13, 2018 12:33
Show Gist options
  • Save ivawzh/9dbef15ef762551d071db32aa25d610e to your computer and use it in GitHub Desktop.
Save ivawzh/9dbef15ef762551d071db32aa25d610e to your computer and use it in GitHub Desktop.
React Class Component VS Recomposed Component
import React from 'react'
import { withStyles } from 'material-ui/styles'
import AppBar from 'material-ui/AppBar'
import Toolbar from 'material-ui/Toolbar'
import Typography from 'material-ui/Typography'
import IconButton from 'material-ui/IconButton'
import Hidden from 'material-ui/Hidden'
import Button from 'material-ui/Button';
import MenuIcon from 'material-ui-icons/Menu'
import Menu, { MenuItem } from 'material-ui/Menu'
import Avatar from 'material-ui/Avatar'
import styles from './top-nav-styles'
import { push } from 'react-router-redux'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { compose, withStateHandlers, withHandlers } from 'recompact'
import { firebaseConnect, isEmpty } from 'react-redux-firebase'
export default compose(
withStyles(styles),
connect((store, ownProps) => ({
auth: store.firebase.auth,
})),
)(TopNav)
function TopNav({
auth,
classes,
}) {
return (
<AppBar className={classes.root} elevation={1} >
<Toolbar>
<Hidden mdUp >
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
</Hidden>
<Typography type="title" color="inherit" className={classes.logo} noWrap>
<Link to="/">DecisionDecision</Link>
</Typography>
{isEmpty(auth) ?
<ComposedLoginButton />
:
<ComposedCurrentUser />
}
</Toolbar>
</AppBar>
)
}
const ComposedCurrentUser = compose(
withStateHandlers(
{ menuAnchorElement: null },
{
onOpenMenu: _props => event => ({ menuAnchorElement: event.currentTarget }),
onCloseMenu: _props => _event => ({ menuAnchorElement: null }),
},
),
connect(
(store, ownProps) => ({
profile: store.firebase.profile,
}),
{ push },
),
firebaseConnect(),
withHandlers({
onLogout: props => _event => {
props.onCloseMenu()
props.firebase.logout()
},
onClickUserProfile: props => _event => {
props.push(`/users/${props.profile.id}`)
},
}),
)(CurrentUser)
function CurrentUser({
profile,
menuAnchorElement,
onOpenMenu,
onCloseMenu,
onClickUserProfile,
onLogout,
}) {
const isMenuOpen = Boolean(menuAnchorElement)
return (
<div>
<IconButton
aria-owns={isMenuOpen ? 'menu-appbar' : null}
aria-haspopup="true"
onClick={onOpenMenu}
color="inherit"
>
<Avatar alt={profile.name} src={profile.avatar} />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={menuAnchorElement}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={isMenuOpen}
onClose={onCloseMenu}
>
<MenuItem onClick={onClickUserProfile}>Profile</MenuItem>
<MenuItem onClick={onLogout}>Logout</MenuItem>
</Menu>
</div>
)
}
const ComposedLoginButton = compose(
firebaseConnect(),
withHandlers({
onGoogleLogin: props => _event => { props.firebase.login({ provider: 'google', type: 'popup' }) },
}),
)(LoginButton)
function LoginButton({ onGoogleLogin }) {
return (
<Button color="inherit" onClick={onGoogleLogin} >
Google Login
</Button>
)
}
import React from 'react'
import { withStyles } from 'material-ui/styles'
import AppBar from 'material-ui/AppBar'
import Toolbar from 'material-ui/Toolbar'
import Typography from 'material-ui/Typography'
import IconButton from 'material-ui/IconButton'
import Hidden from 'material-ui/Hidden'
import Button from 'material-ui/Button';
import MenuIcon from 'material-ui-icons/Menu'
import Menu, { MenuItem } from 'material-ui/Menu'
import { connect } from 'react-redux'
import Avatar from 'material-ui/Avatar'
import { loginGoogle as loginGoogleAction } from 'auth/actions'
import styles from './top-nav-styles'
import { push } from 'react-router-redux'
import { Link } from 'react-router-dom'
class TopNav extends React.Component {
constructor (props) {
super(props)
this.state = {
menuAnchorElement: null,
}
}
handleOpenMenu = event => {
this.setState({ menuAnchorElement: event.currentTarget })
}
handleCloseMenu = () => {
this.setState({ menuAnchorElement: null })
}
renderCurrentUser = () => {
if (!this.props.currentUser.meta.isAuthed) {
return (
<Button color="inherit" onClick={this.props.googleLogin} >
Google Login
</Button>
)
}
const isMenuOpen = Boolean(this.state.menuAnchorElement)
const currentUser = this.props.currentUser.data
return (
<div>
<IconButton
aria-owns={isMenuOpen ? 'menu-appbar' : null}
aria-haspopup="true"
onClick={this.handleOpenMenu}
color="inherit"
>
<Avatar alt={currentUser.name} src={currentUser.avatar} />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={this.state.menuAnchorElement}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={isMenuOpen}
onClose={this.handleCloseMenu}
>
<MenuItem onClick={this.handleClickUserProfile}>Profile</MenuItem>
<MenuItem onClick={this.handleCloseMenu}>Logout (coming soon)</MenuItem>
</Menu>
</div>
)
}
handleClickUserProfile = () => {
this.props.push(`/users/${this.props.currentUser.data.id}`)
this.handleCloseMenu()
}
render() {
const { classes } = this.props
return (
<AppBar className={classes.root} elevation={1} >
<Toolbar>
<Hidden mdUp >
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
</Hidden>
<Typography type="title" color="inherit" className={classes.logo} noWrap>
<Link to="/">DecisionDecision</Link>
</Typography>
{this.renderCurrentUser()}
</Toolbar>
</AppBar>
)
}
}
const StyledTopNav = withStyles(styles)(TopNav)
const ConnectedStyleTopNav = connect(mapStateToProps, { googleLogin: loginGoogleAction, push })(StyledTopNav)
export default ConnectedStyleTopNav
function mapStateToProps(storeState) {
return {
currentUser: storeState.auth,
}
}
diff --git a/src/layouts/components/top-nav.js b/src/layouts/components/top-nav.js
index ea58739..fc0658d 100644
--- a/src/layouts/components/top-nav.js
+++ b/src/layouts/components/top-nav.js
@@ -8,102 +8,123 @@ import Hidden from 'material-ui/Hidden'
import Button from 'material-ui/Button';
import MenuIcon from 'material-ui-icons/Menu'
import Menu, { MenuItem } from 'material-ui/Menu'
-import { connect } from 'react-redux'
import Avatar from 'material-ui/Avatar'
-import { loginGoogle as loginGoogleAction } from 'auth/actions'
import styles from './top-nav-styles'
import { push } from 'react-router-redux'
import { Link } from 'react-router-dom'
+import { connect } from 'react-redux'
+import { compose, withStateHandlers, withHandlers } from 'recompact'
+import { firebaseConnect, isEmpty } from 'react-redux-firebase'
-class TopNav extends React.Component {
- constructor (props) {
- super(props)
- this.state = {
- menuAnchorElement: null,
- }
- }
-
- handleOpenMenu = event => {
- this.setState({ menuAnchorElement: event.currentTarget })
- }
-
- handleCloseMenu = () => {
- this.setState({ menuAnchorElement: null })
- }
+export default compose(
+ withStyles(styles),
+ connect((store, ownProps) => ({
+ auth: store.firebase.auth,
+ })),
+)(TopNav)
- renderCurrentUser = () => {
- if (!this.props.currentUser.meta.isAuthed) {
- return (
- <Button color="inherit" onClick={this.props.googleLogin} >
- Google Login
- </Button>
- )
- }
- const isMenuOpen = Boolean(this.state.menuAnchorElement)
- const currentUser = this.props.currentUser.data
- return (
- <div>
- <IconButton
- aria-owns={isMenuOpen ? 'menu-appbar' : null}
- aria-haspopup="true"
- onClick={this.handleOpenMenu}
- color="inherit"
- >
- <Avatar alt={currentUser.name} src={currentUser.avatar} />
- </IconButton>
- <Menu
- id="menu-appbar"
- anchorEl={this.state.menuAnchorElement}
- anchorOrigin={{
- vertical: 'top',
- horizontal: 'right',
- }}
- transformOrigin={{
- vertical: 'top',
- horizontal: 'right',
- }}
- open={isMenuOpen}
- onClose={this.handleCloseMenu}
- >
- <MenuItem onClick={this.handleClickUserProfile}>Profile</MenuItem>
- <MenuItem onClick={this.handleCloseMenu}>Logout (coming soon)</MenuItem>
- </Menu>
- </div>
- )
- }
+function TopNav({
+ auth,
+ classes,
+}) {
+ return (
+ <AppBar className={classes.root} elevation={1} >
+ <Toolbar>
+ <Hidden mdUp >
+ <IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
+ <MenuIcon />
+ </IconButton>
+ </Hidden>
+ <Typography type="title" color="inherit" className={classes.logo} noWrap>
+ <Link to="/">DecisionDecision</Link>
+ </Typography>
+ {isEmpty(auth) ?
+ <ComposedLoginButton />
+ :
+ <ComposedCurrentUser />
+ }
+ </Toolbar>
+ </AppBar>
+ )
+}
- handleClickUserProfile = () => {
- this.props.push(`/users/${this.props.currentUser.data.id}`)
- this.handleCloseMenu()
- }
+const ComposedCurrentUser = compose(
+ withStateHandlers(
+ { menuAnchorElement: null },
+ {
+ onOpenMenu: _props => event => ({ menuAnchorElement: event.currentTarget }),
+ onCloseMenu: _props => _event => ({ menuAnchorElement: null }),
+ },
+ ),
+ connect(
+ (store, ownProps) => ({
+ profile: store.firebase.profile,
+ }),
+ { push },
+ ),
+ firebaseConnect(),
+ withHandlers({
+ onLogout: props => _event => {
+ props.onCloseMenu()
+ props.firebase.logout()
+ },
+ onClickUserProfile: props => _event => {
+ props.push(`/users/${props.profile.id}`)
+ },
+ }),
+)(CurrentUser)
- render() {
- const { classes } = this.props
- return (
- <AppBar className={classes.root} elevation={1} >
- <Toolbar>
- <Hidden mdUp >
- <IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
- <MenuIcon />
- </IconButton>
- </Hidden>
- <Typography type="title" color="inherit" className={classes.logo} noWrap>
- <Link to="/">DecisionDecision</Link>
- </Typography>
- {this.renderCurrentUser()}
- </Toolbar>
- </AppBar>
- )
- }
+function CurrentUser({
+ profile,
+ menuAnchorElement,
+ onOpenMenu,
+ onCloseMenu,
+ onClickUserProfile,
+ onLogout,
+}) {
+ const isMenuOpen = Boolean(menuAnchorElement)
+ return (
+ <div>
+ <IconButton
+ aria-owns={isMenuOpen ? 'menu-appbar' : null}
+ aria-haspopup="true"
+ onClick={onOpenMenu}
+ color="inherit"
+ >
+ <Avatar alt={profile.name} src={profile.avatar} />
+ </IconButton>
+ <Menu
+ id="menu-appbar"
+ anchorEl={menuAnchorElement}
+ anchorOrigin={{
+ vertical: 'top',
+ horizontal: 'right',
+ }}
+ transformOrigin={{
+ vertical: 'top',
+ horizontal: 'right',
+ }}
+ open={isMenuOpen}
+ onClose={onCloseMenu}
+ >
+ <MenuItem onClick={onClickUserProfile}>Profile</MenuItem>
+ <MenuItem onClick={onLogout}>Logout</MenuItem>
+ </Menu>
+ </div>
+ )
}
-const StyledTopNav = withStyles(styles)(TopNav)
-const ConnectedStyleTopNav = connect(mapStateToProps, { googleLogin: loginGoogleAction, push })(StyledTopNav)
-
-export default ConnectedStyleTopNav
+const ComposedLoginButton = compose(
+ firebaseConnect(),
+ withHandlers({
+ onGoogleLogin: props => _event => { props.firebase.login({ provider: 'google', type: 'popup' }) },
+ }),
+)(LoginButton)
-function mapStateToProps(storeState) {
- return {
- currentUser: storeState.auth,
- }
+function LoginButton({ onGoogleLogin }) {
+ return (
+ <Button color="inherit" onClick={onGoogleLogin} >
+ Google Login
+ </Button>
+ )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment