React hooks function component prevent re-render on state update2019 Community Moderator ElectionReact “after render” code?What is the difference between state and props in React?Can you force a React component to rerender without calling setState?How to conditionally add attributes to React components?How to update parent's state in React?Single animation on stateless React componentDoes React batch state update functions when using hooks?React w/hooks: prevent re-rendering component with a function as propReact Hooks: updating multiple hook states atomicallystate is not being updated when using React Hooks
I've given my players a lot of magic items. Is it reasonable for me to give them harder encounters?
Why would the IRS ask for birth certificates or even audit a small tax return?
Did Amazon pay $0 in taxes last year?
Lock enemy's y-axis when using Vector3.MoveTowards to follow the player
Why do phishing e-mails use faked e-mail addresses instead of the real one?
Book about a time-travel war fought by computers
What is better: yes / no radio, or simple checkbox?
What is a term for a function that when called repeatedly, has the same effect as calling once?
Is there a way to find out the age of climbing ropes?
Deal the cards to the players
How can neutral atoms have exactly zero electric field when there is a difference in the positions of the charges?
“I had a flat in the centre of town, but I didn’t like living there, so …”
Ahoy, Ye Traveler!
Correct physics behind the colors on CD (compact disc)?
Why is my Contribution Detail Report (native CiviCRM Core report) not accurate?
function only contains jump discontinuity but is not piecewise continuous
Can a space-faring robot still function over a billion years?
Wardrobe above a wall with fuse boxes
PTIJ: Is all laundering forbidden during the 9 days?
Sometimes a banana is just a banana
How to mitigate "bandwagon attacking" from players?
Being asked to review a paper in conference one has submitted to
Is there a math equivalent to the conditional ternary operator?
How do you say “my friend is throwing a party, do you wanna come?” in german
React hooks function component prevent re-render on state update
2019 Community Moderator ElectionReact “after render” code?What is the difference between state and props in React?Can you force a React component to rerender without calling setState?How to conditionally add attributes to React components?How to update parent's state in React?Single animation on stateless React componentDoes React batch state update functions when using hooks?React w/hooks: prevent re-rendering component with a function as propReact Hooks: updating multiple hook states atomicallystate is not being updated when using React Hooks
I'm learning about React Hooks which means I'm going to have to move away from classes to function components. Previously in classes I could have class variables independent of the state that I could update without the component re-rendering. Now that I am attempting to re-create a component as a function component with hooks I have ran into the problem that I can't (as far as I know) make variables for that function so the only way to store data is through the useState
hook. However this means my component will re-render whenever that state is updated.
I've illustrated it in the example below where I attempted to re-create a class component as a function component that uses hooks. I want to animate a div if someone clicks on it, but prevent the animation from being called again if the user clicks while it's already animating.
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
If you click on the ClassExample bar(pink) you will see that it does not re-render while animating, however if you click on the FunctionExample bar(red) it will rerender twice while it is animating. This is because I'm using setIsAnimating
which causes the re-render. I know it's probably not very performance-winning but I would like to prevent it if it's at all possible with a function component. Any suggestions/am I doing something wrong?
Update (attempted fix, no solution yet):
Below user lecstor suggested possibly changing the result of useState to let instead of const and then setting it directly let [isAnimating] = React.useState(false);
. This unfortunately does not work either as you can see in the snippet below. Clicking on the red bar will start its animation, clicking on the orange square will make the component re-render, and if you click on the red bar again it will print that isAnimating
is reset to false even though the bar is still animating.
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Update 2(solution):
If you want to have a variable in a function component but not have it re-render the component when it's updated, you can use useRef
instead of useState
. useRef
can be used for more than just dom elements and is actually suggested to be used for instance variables.
See: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
reactjs react-hooks
add a comment |
I'm learning about React Hooks which means I'm going to have to move away from classes to function components. Previously in classes I could have class variables independent of the state that I could update without the component re-rendering. Now that I am attempting to re-create a component as a function component with hooks I have ran into the problem that I can't (as far as I know) make variables for that function so the only way to store data is through the useState
hook. However this means my component will re-render whenever that state is updated.
I've illustrated it in the example below where I attempted to re-create a class component as a function component that uses hooks. I want to animate a div if someone clicks on it, but prevent the animation from being called again if the user clicks while it's already animating.
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
If you click on the ClassExample bar(pink) you will see that it does not re-render while animating, however if you click on the FunctionExample bar(red) it will rerender twice while it is animating. This is because I'm using setIsAnimating
which causes the re-render. I know it's probably not very performance-winning but I would like to prevent it if it's at all possible with a function component. Any suggestions/am I doing something wrong?
Update (attempted fix, no solution yet):
Below user lecstor suggested possibly changing the result of useState to let instead of const and then setting it directly let [isAnimating] = React.useState(false);
. This unfortunately does not work either as you can see in the snippet below. Clicking on the red bar will start its animation, clicking on the orange square will make the component re-render, and if you click on the red bar again it will print that isAnimating
is reset to false even though the bar is still animating.
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Update 2(solution):
If you want to have a variable in a function component but not have it re-render the component when it's updated, you can use useRef
instead of useState
. useRef
can be used for more than just dom elements and is actually suggested to be used for instance variables.
See: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
reactjs react-hooks
add a comment |
I'm learning about React Hooks which means I'm going to have to move away from classes to function components. Previously in classes I could have class variables independent of the state that I could update without the component re-rendering. Now that I am attempting to re-create a component as a function component with hooks I have ran into the problem that I can't (as far as I know) make variables for that function so the only way to store data is through the useState
hook. However this means my component will re-render whenever that state is updated.
I've illustrated it in the example below where I attempted to re-create a class component as a function component that uses hooks. I want to animate a div if someone clicks on it, but prevent the animation from being called again if the user clicks while it's already animating.
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
If you click on the ClassExample bar(pink) you will see that it does not re-render while animating, however if you click on the FunctionExample bar(red) it will rerender twice while it is animating. This is because I'm using setIsAnimating
which causes the re-render. I know it's probably not very performance-winning but I would like to prevent it if it's at all possible with a function component. Any suggestions/am I doing something wrong?
Update (attempted fix, no solution yet):
Below user lecstor suggested possibly changing the result of useState to let instead of const and then setting it directly let [isAnimating] = React.useState(false);
. This unfortunately does not work either as you can see in the snippet below. Clicking on the red bar will start its animation, clicking on the orange square will make the component re-render, and if you click on the red bar again it will print that isAnimating
is reset to false even though the bar is still animating.
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Update 2(solution):
If you want to have a variable in a function component but not have it re-render the component when it's updated, you can use useRef
instead of useState
. useRef
can be used for more than just dom elements and is actually suggested to be used for instance variables.
See: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
reactjs react-hooks
I'm learning about React Hooks which means I'm going to have to move away from classes to function components. Previously in classes I could have class variables independent of the state that I could update without the component re-rendering. Now that I am attempting to re-create a component as a function component with hooks I have ran into the problem that I can't (as far as I know) make variables for that function so the only way to store data is through the useState
hook. However this means my component will re-render whenever that state is updated.
I've illustrated it in the example below where I attempted to re-create a class component as a function component that uses hooks. I want to animate a div if someone clicks on it, but prevent the animation from being called again if the user clicks while it's already animating.
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
If you click on the ClassExample bar(pink) you will see that it does not re-render while animating, however if you click on the FunctionExample bar(red) it will rerender twice while it is animating. This is because I'm using setIsAnimating
which causes the re-render. I know it's probably not very performance-winning but I would like to prevent it if it's at all possible with a function component. Any suggestions/am I doing something wrong?
Update (attempted fix, no solution yet):
Below user lecstor suggested possibly changing the result of useState to let instead of const and then setting it directly let [isAnimating] = React.useState(false);
. This unfortunately does not work either as you can see in the snippet below. Clicking on the red bar will start its animation, clicking on the orange square will make the component re-render, and if you click on the red bar again it will print that isAnimating
is reset to false even though the bar is still animating.
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Update 2(solution):
If you want to have a variable in a function component but not have it re-render the component when it's updated, you can use useRef
instead of useState
. useRef
can be used for more than just dom elements and is actually suggested to be used for instance variables.
See: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const [ isAnimating, setIsAnimating ] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating)
return;
setIsAnimating(true);
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
setIsAnimating(false);
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
const FunctionExample = () =>
console.log("Rendering FunctionExample");
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
let [isAnimating] = React.useState(false);
// Var to force a re-render.
const [ forceCount, forceUpdate ] = React.useState(0);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
console.log("Is animating: ", isAnimating);
if (isAnimating)
return;
isAnimating = true;
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating = false;
,
duration: 5000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
<div onClick=() => forceUpdate(forceCount + 1)
style =
width: '100px',
height: '100px',
marginTop: '12px',
backgroundColor: 'orange'
/>
</div>
);
;
ReactDOM.render( < div > < FunctionExample / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
reactjs react-hooks
reactjs react-hooks
edited 16 hours ago
ApplePearPerson
asked 19 hours ago
ApplePearPersonApplePearPerson
2709
2709
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Use a ref to keep values between function invocations without triggering a render
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look atuseRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…
– ApplePearPerson
16 hours ago
add a comment |
Why is it that you think you can't use internal variables in the same way as you do with classes?
ok, feels a bit dirty but how about mutating the useState state? 8)
nope, that doesn't work as intended
state is reset on re-render
So as this is not related to the actual rendering of the component, maybe our logic needs to be based on the animation itself. This particular problem can be resolved by checking the class that velocity sets on the element while it is being animated.
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration ofisAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why thisisAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.
– ApplePearPerson
17 hours ago
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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%2f55021536%2freact-hooks-function-component-prevent-re-render-on-state-update%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Use a ref to keep values between function invocations without triggering a render
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look atuseRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…
– ApplePearPerson
16 hours ago
add a comment |
Use a ref to keep values between function invocations without triggering a render
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look atuseRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…
– ApplePearPerson
16 hours ago
add a comment |
Use a ref to keep values between function invocations without triggering a render
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Use a ref to keep values between function invocations without triggering a render
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
class ClassExample extends React.Component
_isAnimating = false;
_blockRef = null;
onBlockRef = (ref) =>
if (ref)
this._blockRef = ref;
// Animate the block.
onClick = () =>
if (this._isAnimating)
return;
this._isAnimating = true;
Velocity(this._blockRef,
translateX: 500,
complete: () =>
Velocity(this._blockRef,
translateX: 0,
complete: () =>
this._isAnimating = false;
,
duration: 1000
);
,
duration: 1000
);
;
render()
console.log("Rendering ClassExample");
return(
<div>
<div id='block' onClick=this.onClick ref=this.onBlockRef style= width: '100px', height: '10px', backgroundColor: 'pink'></div>
</div>
);
const FunctionExample = (props) =>
console.log("Rendering FunctionExample");
const isAnimating = React.useRef(false)
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
if (isAnimating.current)
return;
isAnimating.current = true
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
complete: () =>
isAnimating.current = false
,
duration: 1000
);
,
duration: 1000
);
);
return(
<div>
<div id='block' onClick=onClick ref=blockRef style= width: '100px', height: '10px', backgroundColor: 'red'></div>
</div>
);
;
ReactDOM.render(<div><ClassExample/><FunctionExample/></div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
answered 17 hours ago
thedudethedude
2,6841312
2,6841312
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look atuseRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…
– ApplePearPerson
16 hours ago
add a comment |
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look atuseRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…
– ApplePearPerson
16 hours ago
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
well there ya go, thanks dude. I haven't got to playing with useRef yet.. it's just what the doctor ordered.
– lecstor
17 hours ago
Thank you, I didn't even think to look at
useRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…– ApplePearPerson
16 hours ago
Thank you, I didn't even think to look at
useRef
for this but appearently they do suggest it for something like this: reactjs.org/docs/…– ApplePearPerson
16 hours ago
add a comment |
Why is it that you think you can't use internal variables in the same way as you do with classes?
ok, feels a bit dirty but how about mutating the useState state? 8)
nope, that doesn't work as intended
state is reset on re-render
So as this is not related to the actual rendering of the component, maybe our logic needs to be based on the animation itself. This particular problem can be resolved by checking the class that velocity sets on the element while it is being animated.
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration ofisAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why thisisAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.
– ApplePearPerson
17 hours ago
|
show 1 more comment
Why is it that you think you can't use internal variables in the same way as you do with classes?
ok, feels a bit dirty but how about mutating the useState state? 8)
nope, that doesn't work as intended
state is reset on re-render
So as this is not related to the actual rendering of the component, maybe our logic needs to be based on the animation itself. This particular problem can be resolved by checking the class that velocity sets on the element while it is being animated.
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration ofisAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why thisisAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.
– ApplePearPerson
17 hours ago
|
show 1 more comment
Why is it that you think you can't use internal variables in the same way as you do with classes?
ok, feels a bit dirty but how about mutating the useState state? 8)
nope, that doesn't work as intended
state is reset on re-render
So as this is not related to the actual rendering of the component, maybe our logic needs to be based on the animation itself. This particular problem can be resolved by checking the class that velocity sets on the element while it is being animated.
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
Why is it that you think you can't use internal variables in the same way as you do with classes?
ok, feels a bit dirty but how about mutating the useState state? 8)
nope, that doesn't work as intended
state is reset on re-render
So as this is not related to the actual rendering of the component, maybe our logic needs to be based on the animation itself. This particular problem can be resolved by checking the class that velocity sets on the element while it is being animated.
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
const FunctionExample = ( count ) =>
console.log("Rendering FunctionExample", count);
// let isAnimating = false; // no good if component rerenders during animation
// abuse useState var instead?
// let [isAnimating] = React.useState(false);
const blockRef = React.useRef(null);
// Animate the block.
const onClick = React.useCallback(() =>
// use feature of the anim itself
if (/velocity-animating/.test(blockRef.current.className))
return;
console.log("animation triggered");
Velocity(blockRef.current,
translateX: 500,
complete: () =>
Velocity(blockRef.current,
translateX: 0,
,
duration: 1000
);
,
duration: 5000
);
);
return (
<div>
<div
id = 'block'
onClick = onClick
ref = blockRef
style =
width: '100px',
height: '10px',
backgroundColor: 'red'
>
</div>
</div>
);
;
const Counter = () =>
const [count, setCount] = React.useState(0);
return <div>
<FunctionExample count=count />
<button onClick=() => setCount(c => c + 1)>Count</button>
</div>;
ReactDOM.render( < div > < Counter / > < /div>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id='root' style='width: 100%; height: 100%'>
</div>
edited 17 hours ago
answered 18 hours ago
lecstorlecstor
3,3811217
3,3811217
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration ofisAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why thisisAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.
– ApplePearPerson
17 hours ago
|
show 1 more comment
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration ofisAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why thisisAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.
– ApplePearPerson
17 hours ago
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
Those will re-assign everytime the component renders (since the function component is literally the render function) and thus it will overwrite it's previous value. I admit in this example that makes no difference but for components that have extra reasons they might re-render this will be a problem. Say something causes the block to re-render while it's mid-animation, if the user clicks it then it will queue up another animation because isAnimating will have been set to false again even though it's still mid-animation.
– ApplePearPerson
18 hours ago
ok, I see, yeh. You could move the declaration of
isAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.– lecstor
17 hours ago
ok, I see, yeh. You could move the declaration of
isAnimating
outside the component function, but then I guess it'll apply to all rendered instances of the component.– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
Modified it to mutate useState state.. it's not recommended usage, but only because the component won't re-render (afaik), but that's what you want in this instance.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
nope, I'm out of ideas for now. Interesting problem though. I think it might just be something you can't do. A component is ideally just a render of it's props and state and this is trying to get around that.
– lecstor
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why this
isAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.– ApplePearPerson
17 hours ago
It was a nice try. Ideally a component would be a render of it's props and state which is why this
isAnimated
var wasn't either state or props in the class example since it has no influence on rendering itself. Functional components don't seem to have this feature making me unable to store variables other than state which causes the unfortunate re-render.– ApplePearPerson
17 hours ago
|
show 1 more 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.
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%2f55021536%2freact-hooks-function-component-prevent-re-render-on-state-update%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