OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Reactjs, StricMode calling setState twice. Alternative and best practices

  • Thread starter Thread starter Rochin
  • Start date Start date
R

Rochin

Guest
Technical question here. I created a context provider to handle the state of some variables and to create functions to update these variables from other components. It is of my understanding that StricMode calls setStates twice, however, how are we supposed to handle pushing/popping elements from data arrays within states without duplicating these actions.

This is my context.jsx:


Code:
export const BrollProvider = ({ children }) => {
  //These are the states in question
  const [bRollItems, setbRollItems] = useState([]);
  const [timelineData, setTimelineData] = useState([
    {
        id: "0",
        actions: []
    },
  ]);
  
  //This is the function that upon being called updates the states
  const addBrollItemAndAction = (event, currentFrame) => {
    //Some irrelevant variables
    event.preventDefault();
    const bRollItemId = event.dataTransfer.getData('bRollItemId');
    const newAction = {
        id: bRollItemId,
        start: currentFrame / 30,
        end: (currentFrame / 30) + 3,
        isSelected: true,
        effectId: ''
      };
      
    //Next we have the setStates, regardless of the logic within them, they always get called twice
      
    //First setState, doesn't matter if it's called twice since it works on the same object everytime (id === id)
    setbRollItems((prevItems) =>
        prevItems.map((item) =>
            item.id === bRollItemId ? 
                { ...item, 
                    addedToTimeline: true, 
                    startFrame: currentFrame, durationInFrames: 90,
                    width:'85%',
                    transform: 'translate(32px, 37px)'
                } : item
        )
    );

    //This setState adds data to the existing timelineData array, so everytime we call it, 2 identical objects are .pushed to the data array.
    setTimelineData((prevTimelineData) => {
      const updatedData = [...prevTimelineData];
      const lastRow = updatedData[updatedData.length - 1];

      if (lastRow && lastRow.actions.length === 0) {
        lastRow.actions.push(newAction);
      } else {
        const newRow = {
          id: (parseInt(lastRow.id) + 1).toString(),
          actions: [newAction]
        };
        updatedData.push(newRow);
      }
      return updatedData;
    });

  };
  

  return (
    <BrollContext.Provider value={{ bRollItems, setbRollItems, timelineData, setTimelineData, addBrollItemAndAction }}>
      {children}
    </BrollContext.Provider>
  );
};

Now the addBrollItemAndAction function is called from another component (simplified for clarity):


Code:
const MyComponent = ({ propss }) => {
  const { bRollItems, setbRollItems, timelineData, setTimelineData, addBrollItemAndAction } = useMyCustomContextHook(); 
  const currentFrame = someIntValue
  
  const handleBrollDrop = (event) => {
        addBrollItemAndAction(event, currentFrame)
    }
    
  return(
    <div onDrag={handleBrollDrop}>
      <MyOtherComponent/>
    </div>
  )
}

When I disable StrictMode the issue is pretty much fixed, but not the underlying cause. With that being said, what is the best practice to modify arrays of data in developer mode? Specifically with .push() if you don't want the same variable being pushed twice to the same state. And how come updating an array with .push() may cause bugs in the future? Seems pretty straightforward to me. Are we supposed to do workarounds or is this a measure taken by strictMode so we don't use useState for what I'm intending to use it for?

<p>Technical question here. I created a context provider to handle the state of some variables and to create functions to update these variables from other components. It is of my understanding that StricMode calls setStates twice, however, how are we supposed to handle pushing/popping elements from data arrays within states without duplicating these actions.</p>
<p>This is my context.jsx:</p>
<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>export const BrollProvider = ({ children }) => {
//These are the states in question
const [bRollItems, setbRollItems] = useState([]);
const [timelineData, setTimelineData] = useState([
{
id: "0",
actions: []
},
]);

//This is the function that upon being called updates the states
const addBrollItemAndAction = (event, currentFrame) => {
//Some irrelevant variables
event.preventDefault();
const bRollItemId = event.dataTransfer.getData('bRollItemId');
const newAction = {
id: bRollItemId,
start: currentFrame / 30,
end: (currentFrame / 30) + 3,
isSelected: true,
effectId: ''
};

//Next we have the setStates, regardless of the logic within them, they always get called twice

//First setState, doesn't matter if it's called twice since it works on the same object everytime (id === id)
setbRollItems((prevItems) =>
prevItems.map((item) =>
item.id === bRollItemId ?
{ ...item,
addedToTimeline: true,
startFrame: currentFrame, durationInFrames: 90,
width:'85%',
transform: 'translate(32px, 37px)'
} : item
)
);

//This setState adds data to the existing timelineData array, so everytime we call it, 2 identical objects are .pushed to the data array.
setTimelineData((prevTimelineData) => {
const updatedData = [...prevTimelineData];
const lastRow = updatedData[updatedData.length - 1];

if (lastRow && lastRow.actions.length === 0) {
lastRow.actions.push(newAction);
} else {
const newRow = {
id: (parseInt(lastRow.id) + 1).toString(),
actions: [newAction]
};
updatedData.push(newRow);
}
return updatedData;
});

};


return (
<BrollContext.Provider value={{ bRollItems, setbRollItems, timelineData, setTimelineData, addBrollItemAndAction }}>
{children}
</BrollContext.Provider>
);
};</code></pre>
</div>
</div>
</p>
<p>Now the addBrollItemAndAction function is called from another component (simplified for clarity):</p>
<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>const MyComponent = ({ propss }) => {
const { bRollItems, setbRollItems, timelineData, setTimelineData, addBrollItemAndAction } = useMyCustomContextHook();
const currentFrame = someIntValue

const handleBrollDrop = (event) => {
addBrollItemAndAction(event, currentFrame)
}

return(
<div onDrag={handleBrollDrop}>
<MyOtherComponent/>
</div>
)
}</code></pre>
</div>
</div>
</p>
<p>When I disable StrictMode the issue is pretty much fixed, but not the underlying cause. With that being said, what is the best practice to modify arrays of data in developer mode? Specifically with .push() if you don't want the same variable being pushed twice to the same state. And how come updating an array with .push() may cause bugs in the future? Seems pretty straightforward to me. Are we supposed to do workarounds or is this a measure taken by strictMode so we don't use useState for what I'm intending to use it for?</p>
 

Latest posts

Top