React Hooks - can't modify state
up vote
1
down vote
favorite
I'm trying to refactor a class into a stateless component using React
hooks.
The component itself is very simple and I don't see where I'm making a mistake, as it's almost a copy paste from the react docs.
The component is showing a popup when the user clicks on a button (button is passed through props to my component). I'm using typescript
.
I commented the line that fails to do what I want in the hooks
version
Here's my original class:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export interface NodeMenuState {
visible: boolean
}
export class NodeMenu extends React.Component<NodeMenuProps, NodeMenuState> {
state = {
visible: false
}
hide = () => {
this.setState({
visible: false
})
}
handleVisibleChange = (visible: boolean) => {
this.setState({ visible })
}
render() {
return (
<div className={this.props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={this.props.content}
title={this.props.title}
trigger="click"
placement="bottom"
visible={this.state.visible}
onVisibleChange={this.handleVisibleChange}
>
{this.props.button}
</Popover>
</div>
</div>
)
}
}
Here's the React hooks
version:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
console.log(isVisible) // is always `false` despite `visible` being true.
}
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
reactjs typescript react-hooks
add a comment |
up vote
1
down vote
favorite
I'm trying to refactor a class into a stateless component using React
hooks.
The component itself is very simple and I don't see where I'm making a mistake, as it's almost a copy paste from the react docs.
The component is showing a popup when the user clicks on a button (button is passed through props to my component). I'm using typescript
.
I commented the line that fails to do what I want in the hooks
version
Here's my original class:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export interface NodeMenuState {
visible: boolean
}
export class NodeMenu extends React.Component<NodeMenuProps, NodeMenuState> {
state = {
visible: false
}
hide = () => {
this.setState({
visible: false
})
}
handleVisibleChange = (visible: boolean) => {
this.setState({ visible })
}
render() {
return (
<div className={this.props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={this.props.content}
title={this.props.title}
trigger="click"
placement="bottom"
visible={this.state.visible}
onVisibleChange={this.handleVisibleChange}
>
{this.props.button}
</Popover>
</div>
</div>
)
}
}
Here's the React hooks
version:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
console.log(isVisible) // is always `false` despite `visible` being true.
}
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
reactjs typescript react-hooks
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.
– Dan Abramov
Nov 22 at 12:21
Instead,setVisible
triggers a re-render. When we render again, it will be set to a new value.
– Dan Abramov
Nov 22 at 12:22
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm trying to refactor a class into a stateless component using React
hooks.
The component itself is very simple and I don't see where I'm making a mistake, as it's almost a copy paste from the react docs.
The component is showing a popup when the user clicks on a button (button is passed through props to my component). I'm using typescript
.
I commented the line that fails to do what I want in the hooks
version
Here's my original class:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export interface NodeMenuState {
visible: boolean
}
export class NodeMenu extends React.Component<NodeMenuProps, NodeMenuState> {
state = {
visible: false
}
hide = () => {
this.setState({
visible: false
})
}
handleVisibleChange = (visible: boolean) => {
this.setState({ visible })
}
render() {
return (
<div className={this.props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={this.props.content}
title={this.props.title}
trigger="click"
placement="bottom"
visible={this.state.visible}
onVisibleChange={this.handleVisibleChange}
>
{this.props.button}
</Popover>
</div>
</div>
)
}
}
Here's the React hooks
version:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
console.log(isVisible) // is always `false` despite `visible` being true.
}
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
reactjs typescript react-hooks
I'm trying to refactor a class into a stateless component using React
hooks.
The component itself is very simple and I don't see where I'm making a mistake, as it's almost a copy paste from the react docs.
The component is showing a popup when the user clicks on a button (button is passed through props to my component). I'm using typescript
.
I commented the line that fails to do what I want in the hooks
version
Here's my original class:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export interface NodeMenuState {
visible: boolean
}
export class NodeMenu extends React.Component<NodeMenuProps, NodeMenuState> {
state = {
visible: false
}
hide = () => {
this.setState({
visible: false
})
}
handleVisibleChange = (visible: boolean) => {
this.setState({ visible })
}
render() {
return (
<div className={this.props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={this.props.content}
title={this.props.title}
trigger="click"
placement="bottom"
visible={this.state.visible}
onVisibleChange={this.handleVisibleChange}
>
{this.props.button}
</Popover>
</div>
</div>
)
}
}
Here's the React hooks
version:
export interface NodeMenuProps extends PropsNodeButton {
title?: string
content?: JSX.Element
button?: JSX.Element
}
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
console.log(isVisible) // is always `false` despite `visible` being true.
}
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
reactjs typescript react-hooks
reactjs typescript react-hooks
edited Nov 22 at 12:03
Shubham Khatri
75.9k1386126
75.9k1386126
asked Nov 22 at 9:58
Greg Forel
111211
111211
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.
– Dan Abramov
Nov 22 at 12:21
Instead,setVisible
triggers a re-render. When we render again, it will be set to a new value.
– Dan Abramov
Nov 22 at 12:22
add a comment |
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.
– Dan Abramov
Nov 22 at 12:21
Instead,setVisible
triggers a re-render. When we render again, it will be set to a new value.
– Dan Abramov
Nov 22 at 12:22
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.– Dan Abramov
Nov 22 at 12:21
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.– Dan Abramov
Nov 22 at 12:21
Instead,
setVisible
triggers a re-render. When we render again, it will be set to a new value.– Dan Abramov
Nov 22 at 12:22
Instead,
setVisible
triggers a re-render. When we render again, it will be set to a new value.– Dan Abramov
Nov 22 at 12:22
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
Much like setState, the state update behaviour using hooks will also require a re-render and update and hence the change will not be immedialtely visible. If however you try to log state outside of the handleVisibleChange method, you will see the update state
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
}
console.log({ isVisible });
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
Any action that you need to take on the basis of whether the state was update can be done using the useEffect
hook like
useEffect(() => {
// take action when isVisible Changed
}, [isVisible])
Thanks Shubham, I can see the value updating now. However, sinceisVisible
becomestrue
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up sinceisVisible
does change totrue
?
– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Much like setState, the state update behaviour using hooks will also require a re-render and update and hence the change will not be immedialtely visible. If however you try to log state outside of the handleVisibleChange method, you will see the update state
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
}
console.log({ isVisible });
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
Any action that you need to take on the basis of whether the state was update can be done using the useEffect
hook like
useEffect(() => {
// take action when isVisible Changed
}, [isVisible])
Thanks Shubham, I can see the value updating now. However, sinceisVisible
becomestrue
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up sinceisVisible
does change totrue
?
– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
add a comment |
up vote
1
down vote
Much like setState, the state update behaviour using hooks will also require a re-render and update and hence the change will not be immedialtely visible. If however you try to log state outside of the handleVisibleChange method, you will see the update state
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
}
console.log({ isVisible });
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
Any action that you need to take on the basis of whether the state was update can be done using the useEffect
hook like
useEffect(() => {
// take action when isVisible Changed
}, [isVisible])
Thanks Shubham, I can see the value updating now. However, sinceisVisible
becomestrue
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up sinceisVisible
does change totrue
?
– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
add a comment |
up vote
1
down vote
up vote
1
down vote
Much like setState, the state update behaviour using hooks will also require a re-render and update and hence the change will not be immedialtely visible. If however you try to log state outside of the handleVisibleChange method, you will see the update state
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
}
console.log({ isVisible });
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
Any action that you need to take on the basis of whether the state was update can be done using the useEffect
hook like
useEffect(() => {
// take action when isVisible Changed
}, [isVisible])
Much like setState, the state update behaviour using hooks will also require a re-render and update and hence the change will not be immedialtely visible. If however you try to log state outside of the handleVisibleChange method, you will see the update state
export const NodeMenu: React.SFC<NodeMenuProps> = props => {
const [isVisible, setIsVisible] = useState(false)
const hide = () => {
setIsVisible(false)
}
const handleVisibleChange = (visible: boolean) => {
console.log(visible) // visible is `true` when user clicks. It works
setIsVisible(visible) // This does not set isVisible to `true`.
}
console.log({ isVisible });
return (
<div className={props.className}>
<div className={styles.requestNodeMenuIcon}>
<Popover
content={props.content}
title={props.title}
trigger="click"
placement="bottom"
visible={isVisible}
onVisibleChange={handleVisibleChange}
>
{props.button}
</Popover>
</div>
</div>
)
}
Any action that you need to take on the basis of whether the state was update can be done using the useEffect
hook like
useEffect(() => {
// take action when isVisible Changed
}, [isVisible])
answered Nov 22 at 11:38
Shubham Khatri
75.9k1386126
75.9k1386126
Thanks Shubham, I can see the value updating now. However, sinceisVisible
becomestrue
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up sinceisVisible
does change totrue
?
– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
add a comment |
Thanks Shubham, I can see the value updating now. However, sinceisVisible
becomestrue
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up sinceisVisible
does change totrue
?
– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
Thanks Shubham, I can see the value updating now. However, since
isVisible
becomes true
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up since isVisible
does change to true
?– Greg Forel
Nov 22 at 15:32
Thanks Shubham, I can see the value updating now. However, since
isVisible
becomes true
at re-render, I don't understand why the popover doesn't show up. I read the docs about useEffect, but I can't see why I need to use this for the popup to show up since isVisible
does change to true
?– Greg Forel
Nov 22 at 15:32
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
you dont need to use useEffect. That was just an additional information
– Shubham Khatri
Nov 22 at 16:05
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53428291%2freact-hooks-cant-modify-state%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
visible
is a constant defined in your component. There is no possible way that calling any functions could change its value.– Dan Abramov
Nov 22 at 12:21
Instead,
setVisible
triggers a re-render. When we render again, it will be set to a new value.– Dan Abramov
Nov 22 at 12:22