Equivalent to componentDidUpdate using React hooks










5















tldr; How do I simulate componentDidUpdate or otherwise use key with an array to force my component to be reset?



I'm implementing a component which displays a timer and executes a callback when it reaches zero. The intent is for the callback to update a list of objects. The latter component is made of the new React hooks useState and useEffect.



The state contains a reference to the time at which the timer was started, and the time remaining. The effect sets an interval called every second to update the time remaining, and to check whether the callback should be called.



The component is not meant to reschedule a timer, or keep the interval going when it reaches zero, it's supposed to execute the callback and idle. In order for the timer to refresh, I was hoping to pass an array to key which would cause the component's state to be reset, and thus the timer would restart. Unfortunately key must be used with a string, and therefore whether or not my array's reference has changed produces no effect.



I also tried to push changes to the props by passing the array that I was concerned about, but the state was maintained and thus the interval was not reset.



What would be the preferred method to observe shallow changes in an array in order to force a state to be updated solely using the new hooks API?



import React, useState, useEffect from 'react';
import PropTypes from 'prop-types';

function getTimeRemaining(startedAt, delay)
const now = new Date();
const end = new Date(startedAt.getTime() + delay);
return Math.max(0, end.getTime() - now.getTime());


function RefresherTimer(props)
const [startedAt, setStartedAt] = useState(new Date());
const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

useEffect(() =>

if (timeRemaining <= 0)
// The component is set to idle, we do not set the interval.
return;


// Set the interval to refresh the component every second.
const i = setInterval(() =>
const nowRemaining = getTimeRemaining(startedAt, props.delay);
setTimeRemaining(nowRemaining);

if (nowRemaining <= 0)
props.callback();
clearInterval(i);

, 1000);

return () =>
clearInterval(i);
;
);

let message = `Refreshing in $Math.ceil(timeRemaining / 1000)s.`;
if (timeRemaining <= 0)
message = 'Refreshing now...';


return <div>message</div>;


RefresherTimer.propTypes =
callback: PropTypes.func.isRequired,
delay: PropTypes.number
;

RefresherTimer.defaultProps =
delay: 2000
;

export default RefresherTimer;


Attempted to use with key:



<RefresherTimer delay=20000 callback=props.updateListOfObjects key=listOfObjects />


Attempted to use with a props change:



<RefresherTimer delay=20000 callback=props.updateListOfObjects somethingThatChanges=listOfObjects />


listOfObjects refers to an array of objects, where the objects themselves won't necessarily change, so the array should be compared with !==. Typically, the value will be coming from Redux, where the action updateListOfObjects causes the array to be reinitialised like so: newListOfObjects = [...listOfObjects].










share|improve this question
























  • There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

    – Yangshun Tay
    Nov 12 '18 at 7:56











  • Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

    – FMCorz
    Nov 12 '18 at 8:24











  • Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

    – estus
    Nov 12 '18 at 8:26











  • I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

    – FMCorz
    Nov 12 '18 at 8:34











  • Not exactly. I'll provide an answer shortly.

    – estus
    Nov 12 '18 at 8:35















5















tldr; How do I simulate componentDidUpdate or otherwise use key with an array to force my component to be reset?



I'm implementing a component which displays a timer and executes a callback when it reaches zero. The intent is for the callback to update a list of objects. The latter component is made of the new React hooks useState and useEffect.



The state contains a reference to the time at which the timer was started, and the time remaining. The effect sets an interval called every second to update the time remaining, and to check whether the callback should be called.



The component is not meant to reschedule a timer, or keep the interval going when it reaches zero, it's supposed to execute the callback and idle. In order for the timer to refresh, I was hoping to pass an array to key which would cause the component's state to be reset, and thus the timer would restart. Unfortunately key must be used with a string, and therefore whether or not my array's reference has changed produces no effect.



I also tried to push changes to the props by passing the array that I was concerned about, but the state was maintained and thus the interval was not reset.



What would be the preferred method to observe shallow changes in an array in order to force a state to be updated solely using the new hooks API?



import React, useState, useEffect from 'react';
import PropTypes from 'prop-types';

function getTimeRemaining(startedAt, delay)
const now = new Date();
const end = new Date(startedAt.getTime() + delay);
return Math.max(0, end.getTime() - now.getTime());


function RefresherTimer(props)
const [startedAt, setStartedAt] = useState(new Date());
const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

useEffect(() =>

if (timeRemaining <= 0)
// The component is set to idle, we do not set the interval.
return;


// Set the interval to refresh the component every second.
const i = setInterval(() =>
const nowRemaining = getTimeRemaining(startedAt, props.delay);
setTimeRemaining(nowRemaining);

if (nowRemaining <= 0)
props.callback();
clearInterval(i);

, 1000);

return () =>
clearInterval(i);
;
);

let message = `Refreshing in $Math.ceil(timeRemaining / 1000)s.`;
if (timeRemaining <= 0)
message = 'Refreshing now...';


return <div>message</div>;


RefresherTimer.propTypes =
callback: PropTypes.func.isRequired,
delay: PropTypes.number
;

RefresherTimer.defaultProps =
delay: 2000
;

export default RefresherTimer;


Attempted to use with key:



<RefresherTimer delay=20000 callback=props.updateListOfObjects key=listOfObjects />


Attempted to use with a props change:



<RefresherTimer delay=20000 callback=props.updateListOfObjects somethingThatChanges=listOfObjects />


listOfObjects refers to an array of objects, where the objects themselves won't necessarily change, so the array should be compared with !==. Typically, the value will be coming from Redux, where the action updateListOfObjects causes the array to be reinitialised like so: newListOfObjects = [...listOfObjects].










share|improve this question
























  • There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

    – Yangshun Tay
    Nov 12 '18 at 7:56











  • Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

    – FMCorz
    Nov 12 '18 at 8:24











  • Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

    – estus
    Nov 12 '18 at 8:26











  • I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

    – FMCorz
    Nov 12 '18 at 8:34











  • Not exactly. I'll provide an answer shortly.

    – estus
    Nov 12 '18 at 8:35













5












5








5


1






tldr; How do I simulate componentDidUpdate or otherwise use key with an array to force my component to be reset?



I'm implementing a component which displays a timer and executes a callback when it reaches zero. The intent is for the callback to update a list of objects. The latter component is made of the new React hooks useState and useEffect.



The state contains a reference to the time at which the timer was started, and the time remaining. The effect sets an interval called every second to update the time remaining, and to check whether the callback should be called.



The component is not meant to reschedule a timer, or keep the interval going when it reaches zero, it's supposed to execute the callback and idle. In order for the timer to refresh, I was hoping to pass an array to key which would cause the component's state to be reset, and thus the timer would restart. Unfortunately key must be used with a string, and therefore whether or not my array's reference has changed produces no effect.



I also tried to push changes to the props by passing the array that I was concerned about, but the state was maintained and thus the interval was not reset.



What would be the preferred method to observe shallow changes in an array in order to force a state to be updated solely using the new hooks API?



import React, useState, useEffect from 'react';
import PropTypes from 'prop-types';

function getTimeRemaining(startedAt, delay)
const now = new Date();
const end = new Date(startedAt.getTime() + delay);
return Math.max(0, end.getTime() - now.getTime());


function RefresherTimer(props)
const [startedAt, setStartedAt] = useState(new Date());
const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

useEffect(() =>

if (timeRemaining <= 0)
// The component is set to idle, we do not set the interval.
return;


// Set the interval to refresh the component every second.
const i = setInterval(() =>
const nowRemaining = getTimeRemaining(startedAt, props.delay);
setTimeRemaining(nowRemaining);

if (nowRemaining <= 0)
props.callback();
clearInterval(i);

, 1000);

return () =>
clearInterval(i);
;
);

let message = `Refreshing in $Math.ceil(timeRemaining / 1000)s.`;
if (timeRemaining <= 0)
message = 'Refreshing now...';


return <div>message</div>;


RefresherTimer.propTypes =
callback: PropTypes.func.isRequired,
delay: PropTypes.number
;

RefresherTimer.defaultProps =
delay: 2000
;

export default RefresherTimer;


Attempted to use with key:



<RefresherTimer delay=20000 callback=props.updateListOfObjects key=listOfObjects />


Attempted to use with a props change:



<RefresherTimer delay=20000 callback=props.updateListOfObjects somethingThatChanges=listOfObjects />


listOfObjects refers to an array of objects, where the objects themselves won't necessarily change, so the array should be compared with !==. Typically, the value will be coming from Redux, where the action updateListOfObjects causes the array to be reinitialised like so: newListOfObjects = [...listOfObjects].










share|improve this question
















tldr; How do I simulate componentDidUpdate or otherwise use key with an array to force my component to be reset?



I'm implementing a component which displays a timer and executes a callback when it reaches zero. The intent is for the callback to update a list of objects. The latter component is made of the new React hooks useState and useEffect.



The state contains a reference to the time at which the timer was started, and the time remaining. The effect sets an interval called every second to update the time remaining, and to check whether the callback should be called.



The component is not meant to reschedule a timer, or keep the interval going when it reaches zero, it's supposed to execute the callback and idle. In order for the timer to refresh, I was hoping to pass an array to key which would cause the component's state to be reset, and thus the timer would restart. Unfortunately key must be used with a string, and therefore whether or not my array's reference has changed produces no effect.



I also tried to push changes to the props by passing the array that I was concerned about, but the state was maintained and thus the interval was not reset.



What would be the preferred method to observe shallow changes in an array in order to force a state to be updated solely using the new hooks API?



import React, useState, useEffect from 'react';
import PropTypes from 'prop-types';

function getTimeRemaining(startedAt, delay)
const now = new Date();
const end = new Date(startedAt.getTime() + delay);
return Math.max(0, end.getTime() - now.getTime());


function RefresherTimer(props)
const [startedAt, setStartedAt] = useState(new Date());
const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

useEffect(() =>

if (timeRemaining <= 0)
// The component is set to idle, we do not set the interval.
return;


// Set the interval to refresh the component every second.
const i = setInterval(() =>
const nowRemaining = getTimeRemaining(startedAt, props.delay);
setTimeRemaining(nowRemaining);

if (nowRemaining <= 0)
props.callback();
clearInterval(i);

, 1000);

return () =>
clearInterval(i);
;
);

let message = `Refreshing in $Math.ceil(timeRemaining / 1000)s.`;
if (timeRemaining <= 0)
message = 'Refreshing now...';


return <div>message</div>;


RefresherTimer.propTypes =
callback: PropTypes.func.isRequired,
delay: PropTypes.number
;

RefresherTimer.defaultProps =
delay: 2000
;

export default RefresherTimer;


Attempted to use with key:



<RefresherTimer delay=20000 callback=props.updateListOfObjects key=listOfObjects />


Attempted to use with a props change:



<RefresherTimer delay=20000 callback=props.updateListOfObjects somethingThatChanges=listOfObjects />


listOfObjects refers to an array of objects, where the objects themselves won't necessarily change, so the array should be compared with !==. Typically, the value will be coming from Redux, where the action updateListOfObjects causes the array to be reinitialised like so: newListOfObjects = [...listOfObjects].







javascript reactjs react-hooks






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 12 '18 at 8:32







FMCorz

















asked Nov 12 '18 at 4:24









FMCorzFMCorz

887610




887610












  • There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

    – Yangshun Tay
    Nov 12 '18 at 7:56











  • Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

    – FMCorz
    Nov 12 '18 at 8:24











  • Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

    – estus
    Nov 12 '18 at 8:26











  • I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

    – FMCorz
    Nov 12 '18 at 8:34











  • Not exactly. I'll provide an answer shortly.

    – estus
    Nov 12 '18 at 8:35

















  • There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

    – Yangshun Tay
    Nov 12 '18 at 7:56











  • Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

    – FMCorz
    Nov 12 '18 at 8:24











  • Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

    – estus
    Nov 12 '18 at 8:26











  • I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

    – FMCorz
    Nov 12 '18 at 8:34











  • Not exactly. I'll provide an answer shortly.

    – estus
    Nov 12 '18 at 8:35
















There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

– Yangshun Tay
Nov 12 '18 at 7:56





There's no componentDidReceiveProps lifecycle method. Did you mean componentWillReceiveProps?

– Yangshun Tay
Nov 12 '18 at 7:56













Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

– FMCorz
Nov 12 '18 at 8:24





Whoops, I did. In fact, I'm going to edit and refer to componentDidUpdate as using componentWillReceiveProps is discouraged.

– FMCorz
Nov 12 '18 at 8:24













Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

– estus
Nov 12 '18 at 8:26





Please, provide stackoverflow.com/help/mcve . What exactly is ListOfObjects?

– estus
Nov 12 '18 at 8:26













I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

– FMCorz
Nov 12 '18 at 8:34





I added some information regarding that array, however it doesn't really matter what this variable represents, so long as it's understood that it should be shallow-compared using !==.

– FMCorz
Nov 12 '18 at 8:34













Not exactly. I'll provide an answer shortly.

– estus
Nov 12 '18 at 8:35





Not exactly. I'll provide an answer shortly.

– estus
Nov 12 '18 at 8:35












3 Answers
3






active

oldest

votes


















1














In short, you want to reset your timer when the reference of the array changes, right ?
If so, you will need to use some diffing mechanism, a pure hooks based solution would take advantage of the second parameter of useEffect, like so:



function RefresherTimer(props) {
const [startedAt, setStartedAt] = useState(new Date());
const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

//reset part, lets just set startedAt to now
useEffect(() => setStartedAt(new Date()),
//important part
[props.listOfObjects] // <= means: run this effect only if any variable
// in that array is different from the last run
)

useEffect(() =>
// everything with intervals, and the render



More information about this behaviour here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects






share|improve this answer






























    1














    The withRef creates an "instance variable" in functional component. It acts a flag to indicate whether it is in mount or update phase without updating state.



    const mounted = useRef();
    useEffect(() =>
    if (!mounted.current)
    mounted.current = true;
    else
    // do componentDidUpate logic

    );





    share|improve this answer






























      0














      A way to remount a component is to provide new key property. It's not necessarily a string but it will be coerced to a string internally, so if listOfObjects is a string, it's expected that key is compared internally with listOfObjects.toString().



      Any random key can be used, e.g. uuid or Math.random(). Shallow comparison of listOfObjects can be performed in parent component to provide new key. useMemo hook can be used in parent state to conditionally update remount key, and listOfObjects can be used as a list of parameters that need to be memoized. Here's an example:



       const remountKey = useMemo(() => Math.random(), listOfObjects);

      return (
      <div>
      <RefresherTimer delay=3000 callback=() => console.log('refreshed') key=remountKey />
      </div>
      );


      As an alternative to remount key, child component could be able to reset own state and expose a callback to trigger a reset.



      Doing shallow comparison of listOfObjects inside child component would be an antipattern because this requires it to be aware of parent component implementation.






      share|improve this answer

























      • Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

        – FMCorz
        Nov 12 '18 at 9:25











      • Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

        – estus
        Nov 12 '18 at 9:36











      • If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

        – estus
        Nov 12 '18 at 10:04










      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
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255951%2fequivalent-to-componentdidupdate-using-react-hooks%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      In short, you want to reset your timer when the reference of the array changes, right ?
      If so, you will need to use some diffing mechanism, a pure hooks based solution would take advantage of the second parameter of useEffect, like so:



      function RefresherTimer(props) {
      const [startedAt, setStartedAt] = useState(new Date());
      const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

      //reset part, lets just set startedAt to now
      useEffect(() => setStartedAt(new Date()),
      //important part
      [props.listOfObjects] // <= means: run this effect only if any variable
      // in that array is different from the last run
      )

      useEffect(() =>
      // everything with intervals, and the render



      More information about this behaviour here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects






      share|improve this answer



























        1














        In short, you want to reset your timer when the reference of the array changes, right ?
        If so, you will need to use some diffing mechanism, a pure hooks based solution would take advantage of the second parameter of useEffect, like so:



        function RefresherTimer(props) {
        const [startedAt, setStartedAt] = useState(new Date());
        const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

        //reset part, lets just set startedAt to now
        useEffect(() => setStartedAt(new Date()),
        //important part
        [props.listOfObjects] // <= means: run this effect only if any variable
        // in that array is different from the last run
        )

        useEffect(() =>
        // everything with intervals, and the render



        More information about this behaviour here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects






        share|improve this answer

























          1












          1








          1







          In short, you want to reset your timer when the reference of the array changes, right ?
          If so, you will need to use some diffing mechanism, a pure hooks based solution would take advantage of the second parameter of useEffect, like so:



          function RefresherTimer(props) {
          const [startedAt, setStartedAt] = useState(new Date());
          const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

          //reset part, lets just set startedAt to now
          useEffect(() => setStartedAt(new Date()),
          //important part
          [props.listOfObjects] // <= means: run this effect only if any variable
          // in that array is different from the last run
          )

          useEffect(() =>
          // everything with intervals, and the render



          More information about this behaviour here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects






          share|improve this answer













          In short, you want to reset your timer when the reference of the array changes, right ?
          If so, you will need to use some diffing mechanism, a pure hooks based solution would take advantage of the second parameter of useEffect, like so:



          function RefresherTimer(props) {
          const [startedAt, setStartedAt] = useState(new Date());
          const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

          //reset part, lets just set startedAt to now
          useEffect(() => setStartedAt(new Date()),
          //important part
          [props.listOfObjects] // <= means: run this effect only if any variable
          // in that array is different from the last run
          )

          useEffect(() =>
          // everything with intervals, and the render



          More information about this behaviour here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 16 '18 at 12:36









          Bear-FootBear-Foot

          22819




          22819























              1














              The withRef creates an "instance variable" in functional component. It acts a flag to indicate whether it is in mount or update phase without updating state.



              const mounted = useRef();
              useEffect(() =>
              if (!mounted.current)
              mounted.current = true;
              else
              // do componentDidUpate logic

              );





              share|improve this answer



























                1














                The withRef creates an "instance variable" in functional component. It acts a flag to indicate whether it is in mount or update phase without updating state.



                const mounted = useRef();
                useEffect(() =>
                if (!mounted.current)
                mounted.current = true;
                else
                // do componentDidUpate logic

                );





                share|improve this answer

























                  1












                  1








                  1







                  The withRef creates an "instance variable" in functional component. It acts a flag to indicate whether it is in mount or update phase without updating state.



                  const mounted = useRef();
                  useEffect(() =>
                  if (!mounted.current)
                  mounted.current = true;
                  else
                  // do componentDidUpate logic

                  );





                  share|improve this answer













                  The withRef creates an "instance variable" in functional component. It acts a flag to indicate whether it is in mount or update phase without updating state.



                  const mounted = useRef();
                  useEffect(() =>
                  if (!mounted.current)
                  mounted.current = true;
                  else
                  // do componentDidUpate logic

                  );






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 21 '18 at 6:27









                  Morgan ChengMorgan Cheng

                  28.4k52151212




                  28.4k52151212





















                      0














                      A way to remount a component is to provide new key property. It's not necessarily a string but it will be coerced to a string internally, so if listOfObjects is a string, it's expected that key is compared internally with listOfObjects.toString().



                      Any random key can be used, e.g. uuid or Math.random(). Shallow comparison of listOfObjects can be performed in parent component to provide new key. useMemo hook can be used in parent state to conditionally update remount key, and listOfObjects can be used as a list of parameters that need to be memoized. Here's an example:



                       const remountKey = useMemo(() => Math.random(), listOfObjects);

                      return (
                      <div>
                      <RefresherTimer delay=3000 callback=() => console.log('refreshed') key=remountKey />
                      </div>
                      );


                      As an alternative to remount key, child component could be able to reset own state and expose a callback to trigger a reset.



                      Doing shallow comparison of listOfObjects inside child component would be an antipattern because this requires it to be aware of parent component implementation.






                      share|improve this answer

























                      • Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                        – FMCorz
                        Nov 12 '18 at 9:25











                      • Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                        – estus
                        Nov 12 '18 at 9:36











                      • If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                        – estus
                        Nov 12 '18 at 10:04















                      0














                      A way to remount a component is to provide new key property. It's not necessarily a string but it will be coerced to a string internally, so if listOfObjects is a string, it's expected that key is compared internally with listOfObjects.toString().



                      Any random key can be used, e.g. uuid or Math.random(). Shallow comparison of listOfObjects can be performed in parent component to provide new key. useMemo hook can be used in parent state to conditionally update remount key, and listOfObjects can be used as a list of parameters that need to be memoized. Here's an example:



                       const remountKey = useMemo(() => Math.random(), listOfObjects);

                      return (
                      <div>
                      <RefresherTimer delay=3000 callback=() => console.log('refreshed') key=remountKey />
                      </div>
                      );


                      As an alternative to remount key, child component could be able to reset own state and expose a callback to trigger a reset.



                      Doing shallow comparison of listOfObjects inside child component would be an antipattern because this requires it to be aware of parent component implementation.






                      share|improve this answer

























                      • Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                        – FMCorz
                        Nov 12 '18 at 9:25











                      • Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                        – estus
                        Nov 12 '18 at 9:36











                      • If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                        – estus
                        Nov 12 '18 at 10:04













                      0












                      0








                      0







                      A way to remount a component is to provide new key property. It's not necessarily a string but it will be coerced to a string internally, so if listOfObjects is a string, it's expected that key is compared internally with listOfObjects.toString().



                      Any random key can be used, e.g. uuid or Math.random(). Shallow comparison of listOfObjects can be performed in parent component to provide new key. useMemo hook can be used in parent state to conditionally update remount key, and listOfObjects can be used as a list of parameters that need to be memoized. Here's an example:



                       const remountKey = useMemo(() => Math.random(), listOfObjects);

                      return (
                      <div>
                      <RefresherTimer delay=3000 callback=() => console.log('refreshed') key=remountKey />
                      </div>
                      );


                      As an alternative to remount key, child component could be able to reset own state and expose a callback to trigger a reset.



                      Doing shallow comparison of listOfObjects inside child component would be an antipattern because this requires it to be aware of parent component implementation.






                      share|improve this answer















                      A way to remount a component is to provide new key property. It's not necessarily a string but it will be coerced to a string internally, so if listOfObjects is a string, it's expected that key is compared internally with listOfObjects.toString().



                      Any random key can be used, e.g. uuid or Math.random(). Shallow comparison of listOfObjects can be performed in parent component to provide new key. useMemo hook can be used in parent state to conditionally update remount key, and listOfObjects can be used as a list of parameters that need to be memoized. Here's an example:



                       const remountKey = useMemo(() => Math.random(), listOfObjects);

                      return (
                      <div>
                      <RefresherTimer delay=3000 callback=() => console.log('refreshed') key=remountKey />
                      </div>
                      );


                      As an alternative to remount key, child component could be able to reset own state and expose a callback to trigger a reset.



                      Doing shallow comparison of listOfObjects inside child component would be an antipattern because this requires it to be aware of parent component implementation.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Nov 12 '18 at 10:07

























                      answered Nov 12 '18 at 9:11









                      estusestus

                      73.8k22108224




                      73.8k22108224












                      • Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                        – FMCorz
                        Nov 12 '18 at 9:25











                      • Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                        – estus
                        Nov 12 '18 at 9:36











                      • If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                        – estus
                        Nov 12 '18 at 10:04

















                      • Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                        – FMCorz
                        Nov 12 '18 at 9:25











                      • Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                        – estus
                        Nov 12 '18 at 9:36











                      • If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                        – estus
                        Nov 12 '18 at 10:04
















                      Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                      – FMCorz
                      Nov 12 '18 at 9:25





                      Creating a parent component to do the comparison is only pushing my problem outside of my component, how do I achieve the comparison using hooks? Note that just using a random key means that any re-render of the parent component will cause the timer to be lost, this is not an option. Also listOfObjects is an array of objects, so coercing it to string won't work: [object Object],[object Object],[object Object]". Lastly, as you said it yourself, the 3rd option is an antipattern.

                      – FMCorz
                      Nov 12 '18 at 9:25













                      Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                      – estus
                      Nov 12 '18 at 9:36





                      Yes, coercing listOfObjects won't work, I mentioned this to explain why current attempt doesn't work. Parent component is the component where you use <RefresherTimer>, it already exists. using a random key means that any re-render of the parent component will cause the timer to be lost - it doesn't mean that. It basically should be key=this.state.remountKey where remountKey is something like shallowEqual(preState.listOfObjects, newState.listOfObjects) && prevState.remountKey || Math.random(). If you use Redux, remountKey should likely be calculated there.

                      – estus
                      Nov 12 '18 at 9:36













                      If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                      – estus
                      Nov 12 '18 at 10:04





                      If you want to use hooks, useMemo hook can be likely be used in parent component to calculate remountKey. I provided an example that shows the idea. Using an equivalent to componentDidUpdate in child component would be a mistake because this requires it to be aware of listOfObjects while it shouldn't.

                      – estus
                      Nov 12 '18 at 10:04

















                      draft saved

                      draft discarded
















































                      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.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53255951%2fequivalent-to-componentdidupdate-using-react-hooks%23new-answer', 'question_page');

                      );

                      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







                      Popular posts from this blog

                      𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

                      Crossroads (UK TV series)

                      ữḛḳṊẴ ẋ,Ẩṙ,ỹḛẪẠứụỿṞṦ,Ṉẍừ,ứ Ị,Ḵ,ṏ ṇỪḎḰṰọửḊ ṾḨḮữẑỶṑỗḮṣṉẃ Ữẩụ,ṓ,ḹẕḪḫỞṿḭ ỒṱṨẁṋṜ ḅẈ ṉ ứṀḱṑỒḵ,ḏ,ḊḖỹẊ Ẻḷổ,ṥ ẔḲẪụḣể Ṱ ḭỏựẶ Ồ Ṩ,ẂḿṡḾồ ỗṗṡịṞẤḵṽẃ ṸḒẄẘ,ủẞẵṦṟầṓế