我想使用react钩子将此React类组件更改为react功能组件。我了解如何使用useState设置我的初始状态,但是我需要结构和语法方面的帮助。我想使用无法在类组件中使用的history()。
我不确定如何正确执行此操作,希望能获得一些帮助和指导
我做了这么远的事情:
export function ProfileMenu(){
const history = useHistory()
const ref = useRef()
const [showUserMenu, setShowUserMenu] = useState(false)
const [showProfile, setShowProfile] = useState(false)
const [showPasswordPopup, setShowPasswordPopup] = useState(false)
const [oldPasswordError, setOldPasswordError] = useState(null)
const [newPasswordConfirmed, setNewPassswordConfirmed] = useState(null)
const [newPasswordMatchError, setNewPasswordMatchError] = useState(null)
userMenuRef = React.createRef(),
renderUserIcon = () => {
return (
<div
className="ml-1"
ref={this.userMenuRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => this.setState({ showUserMenu: !this.state.showUserMenu })}
>
<Avatar firstName={this.props.firstName} lastName={this.props.lastName} suspended={false} />
<Popper
open={this.state.showUserMenu}
anchorEl={this.userMenuRef.current}
transition
disablePortal
placement="bottom-end"
className={styles.logout}
>
{({ TransitionProps, placement }) => (
<Grow {...TransitionProps} style={{ transformOrigin: 'right bottom' }}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={() => this.setState({ showUserMenu: false })}>
<UserMenu>
<UserMenuItem
onClick={() => this.setState({ showProfile: !this.state.showProfile })}
>
Edit Profile
</UserMenuItem>
<UserMenuItem
onClick={() => history.push('/editprofile')}
>
Change Password
</UserMenuItem>
<UserMenuItem onClick={() => this.props.logout()}>Log out</UserMenuItem>
</UserMenu>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
)
}
}
原始组件:
export class Header extends Component {
state = {
showUserMenu: false,
showProfile: false,
showPasswordPopup: false,
oldPasswordError: null,
newPasswordConfirmed: null,
newPasswordMatchError: null,
}
userMenuRef = React.createRef()
renderUserIcon() {
return (
<div
className="ml-1"
ref={this.userMenuRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => this.setState({ showUserMenu: !this.state.showUserMenu })}
>
<Avatar firstName={this.props.firstName} lastName={this.props.lastName} suspended={false} />
<Popper
open={this.state.showUserMenu}
anchorEl={this.userMenuRef.current}
transition
disablePortal
placement="bottom-end"
className={styles.logout}
>
{({ TransitionProps, placement }) => (
<Grow {...TransitionProps} style={{ transformOrigin: 'right bottom' }}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={() => this.setState({ showUserMenu: false })}>
<UserMenu>
<UserMenuItem
onClick={() => this.setState({ showProfile: !this.state.showProfile })}
>
Edit Profile
</UserMenuItem>
<UserMenuItem
onClick={() => history.push('/editprofile')}
>
Change Password
</UserMenuItem>
<UserMenuItem onClick={() => this.props.logout()}>Log out</UserMenuItem>
</UserMenu>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
)
}
renderNavContent() {
return (
<div className={styles.border}>
{this.props.tabs.map(({ text, url, exact = true }, i) => (
<NavLink
key={i}
to={url}
className={styles.tab}
activeClassName={
matchPath(window.location.pathname, { path: url, exact }) ? styles.active : styles.tab
}
>
{text}
</NavLink>
))}
</div>
)
}
renderProfilePopup() {
const onClose = () =>
this.setState({
showProfile: false,
})
return (
<Mutation
mutation={UPDATE_USER}
key={'UPDATE_USER'}
update={(cache, { data: { updateUser } }) => {
this.props.extendUser(updateUser)
}}
>
{(mutation, { error }) => (
<EditContact
open={this.state.showProfile}
user={this.props.user}
error={error}
onClose={onClose}
_onSubmit={async (form) => {
await mutation({ variables: { user: form } })
this.setState({ showProfile: false })
this.props.enqueueSnackbar('User was updated successfully', { variant: 'success' })
}}
/>
)}
</Mutation>
)
}
renderPasswordPopup() {
const onClose = () => {
this.setState({
showPasswordPopup: false,
})
}
return (
<ChangePasswordModal
open={this.state.showPasswordPopup}
onClose={onClose}
user={this.props.user}
_onSubmit={async (form) => {
await this.props.changePassword(
form.oldPassword,
form.newPassword,
form.newPasswordConfirmed
)
this.props.enqueueSnackbar('Password was updated successfully', { variant: 'success' })
}}
/>
)
}
render() {
return (
<div className={styles.header}>
<Grid container justify="space-between" alignItems="center">
<Grid>
<Grid container alignItems="center">
<Hidden mdUp>
<IconButton
color="inherit"
onClick={() => this.props.setMenuState(true)}
edge="start"
>
<MenuIcon />
</IconButton>
</Hidden>
<div className={styles.organization}>{this.props.organization}</div>
</Grid>
</Grid>
<Grid>
<Grid container justify="flex-end" alignItems="center">
<Tooltip className="mx-2" title="Support">
<SupportIcon />
</Tooltip>
<Tooltip className="mx-2" title="Notifications">
<div className="ak-trigger">
<NotificationsIcon />
<AnnounceKit
catchClick=".ak-trigger"
widget={process.env.REACT_APP_ANNOUNCE_KIT_WIDGET_URL}
/>
</div>
</Tooltip>
<div className={classnames('mx-2', styles.user)}>
<Hidden xsDown>
<div onClick={() => this.setState({ showUserMenu: !this.state.showUserMenu })}>
<div>
{this.props.firstName} {this.props.lastName}
</div>
<div>{this.props.email}</div>
</div>
</Hidden>
{this.renderUserIcon()}
</div>
</Grid>
</Grid>
</Grid>
{this.renderProfilePopup()}
{this.renderPasswordPopup()}
<h1 className={styles.title}>{this.props.title}</h1>
{this.renderNavContent()}
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withSnackbar(Header))