Prevent React hook from being called when state changes - reactjs

I noticed that when you use useState in a hook and then use setState to change the value that is being cached, the hook will be called again and re-render the component. While this may be desired most of the time, I have one case where I don't want to re-render when the state changes. This case is when you have a navigation menu (tabs) at the top of the page and when you click on a tab, it shows content in a pane beneath it. I really only want to hide the content for the tab that is currently shown and then display the content for the tab that is selected. When content is hidden, this is essentially setting the css "display" style to "none". This is desirable to preserve the state of the content's pane and also avoid effects like retrieving data.
I can think of one solution to handle this but it does require splitting the components into isolated modules. I am curious though whether there is a way to change state but without having the side effect of a component being re-rendered.

Related

React & Canvas: changing state is breaking Canvas functions

I am trying to use a parent component to control animations in a child Canvas element. Specifically I want an animation to happen when a user inputs a correct answer.
It works until the user changes the state in the parent component, and then it no longer works.
I've made a stripped-back, minimal version of my code here to show my issue: https://codesandbox.io/s/epic-leaf-08jqvy?file=/src/App.js
My desired behaviour is that the red box bounces when a user clicks submit. That happens if they don't type anything in the input box, but as soon as you enter anything into there - changing state and re-rendering the component - the button no longer triggers the animation in the Canvas child component.
As far as I can tell, the issue is to do with changing the state when inputing text. If I make a version where the input is just assigned to a variable, it works fine, but I need to be able to use state and re-render other parts of it.
I have put a console.log in the jump() function, so I can see that it is being called, but no animation is taking place in the canvas.
I assume that what's happening is that everything is being re-rendered when the state changes, and so the useRef is no longer tracking to the right thing.
Things I've tried:
putting the canvas in a memoized component to prevent it from re-rendering
using eventlisteners to see if I can trigger the animations in other ways - keydown ones work, but I need the user to be able to type, so I tried other ones (like hashchange or audio.play) but neither of those worked.
You can see the thing I'm actually trying to build here: https://papaya-platypus-86565f.netlify.app/play Basically users answer questions and an animation plays depending on whether they're right or wrong, to give it a game-y feel.
Thanks!
I like your red box as well as your reasoning. Yes, the input state changing on keystroke is causing the entire App component to re-render. Note that your App.js component has a lot going on (all good stuff), such as your Box class instantiation, your canvas instantiation, etc.
The key is to break your components into smaller parts, particularly separating stateful components from non-stateful components. We don't want your canvas re-mounting on every input change, so we make them sibling components!
Here's a working example of your code, just in smaller components:
https://codesandbox.io/s/strange-julien-d3n4zm
I hope this helps.

Hook re-render whole page on single change in a sub component

I create 2 Text Boxes one with hook and the another one with the old style, now in Hook mode when the user input change the textbox value the whole page rendered, but with old style there only the text-box rendered not the whole page, if you have the complex page with many objects like (Data Table, form, buttons, inputs, etc..) the single change on one of these components forced to re-render everything and it decease performance, for example typing in the text-box take time to effect on page and the delay time is more than user typing speed.
the one workaround solution is using the callbacks and useMem but if the page is complex(lots of objects as described, and all of these objects has many properties the callback and useMem is very very complicated to handle single object property.
SandBox Example
This is exactly how react hooks should work. what will cause a rerender in react? two things:
change in props
change in hooks or say in a better way hooks state
in the second case, the useInput state is changing so that causes a rerender and it's absolutely normal behavior. I think using custom hook in that way is not a good practice.
I recommend reading this article for more information on react rendering: https://www.codebeast.dev/usestate-vs-useref-re-render-or-not/

Hiding Components in order to keep their state in React

I have a component with children. I would like these to be shown or not depending on the press of a button. I can do this by creating a state variable childrenVisible, and then rendering or not depending on it.
But I have noticed that if I have state on a child Component it will get reset when toggling childrenVisible. I think this is because components gets destroyed when not rendered on a re-render.
I would like to keep the elements around, so I can keep their state, but just hide them depending on childrenVisible. Is this possible in React?

Highlight a single button instance in a complex React page

My page is composed of hierarchy of classes and many reusable components. Multiple instances of a button component can exist anywhere in the page and on click they fire actions that populate different types of data in a common sidebar list component.
The requirement is to highlight the button that was last clicked to load the data in that sidebar list. Of course, it also means to remove highlighting from the previous button. Since these button can exist in different components, I cannot manage state in one parent component.
I am not able to find a solution in pure React. I don't want to use jQuery rather just stick to React. Note I do use Redux in the app though and would be fine with leveraging Redux state if required.
You should most definitely use Redux. You'll need to create a variable in Redux that gets updated whenever an action takes place that would require you to highlight the button on the page. Then use conditional styling for the button based on that variable.

Tabs2 re-renders on state change, effectively rendering the renderActiveTabPanelOnly prop useless

Not sure what I'm missing here: looking at the example source code in both uncontrolled mode and controlled mode call a setState method on tab change (https://github.com/palantir/blueprint/blob/master/packages/core/examples/tabs2Example.tsx). However, in my environment, this call of setState in my onChange listener is re-rendering the component containing my Tabs2 element meaning that only 1 of my tab panels (specifically the one I'm looking at) are preserved.
I think you may be misunderstanding the purpose of the renderActiveTabPanelOnly prop:
when true, only the active tab is mounted in the DOM (the other non-active tabs are removed).
when false, all tabs are mounted in the DOM but only the active tab is visible (the non-active tabs are hidden via CSS).
Does that clarify the usage?

Resources