React state issue (a bad setState?) when trying to show a component composed with styled components - reactjs

Now I am not entirely sure what confluence of things brought this issue to a head, but lets start with my minimal reproduction
What am I trying to do
I want to show a styled element that is composed from various "inherited" members inside of a modal. Once the element is clicked, it will dismiss the modal.
Actual results
For some reason the element triggers it's onClick early, as soon as you click the button that is actually supposed to open the modal. It is only because it's a styled component (I think). If I change the element from a Para to a normal p, it behaves correctly.
I'm wondering, what can cause this? Is it that I nested too much? The error I get is
Warning: Cannot update a component (`App`) while rendering a different component (`Styled(Styled(styled.div))`). To locate the bad setState() call inside `Styled(Styled(styled.div))`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render

The issue here is that you're spreading ...rest in your Para styled-component. Remove it from ./Para.js and it should work as expected

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.

Pass context when render components programmatically

In my REACT application, I'm trying to render a Component programmatically, but pasing to it any REACT context. Let me show you a simple example with this sandbox: https://codesandbox.io/s/kind-carson-u0hup?file=/src/App.tsx
As you can see, what I want to do is rendering <Dialog> programmatically when I click a button. But, inside that <Dialog>, I want to use any context created on the React Tree.
Unfortunately, I am aware that React.render does not pass any context, thus this cannot work: if you click on the button, you will see that, while the context in <InnerComponent> provides the value 'FooBar'. inside <Dialog> I have the default value 'initialValue'.
Thus, the question is, is there any way I can programmatically render a component, AND passing to its any kind of context?
I'm aware that React.createPortal does pass the context, but that method MUST be called inside the return statement of a component, while instead, in my case, I render the <Dialog> after a click on the Button.
Also, yes, I could always have the <Dialog> rendered, and use a prop isVisible.. But this is a simpler example.
I've read several things (some of these in the following links), but none of these really helped me:
https://github.com/facebook/react/issues/17974
Is it possible to pass context into a component instantiated with ReactDOM.render?
Why component rendered with ReactDOM.render loses react-redux context (Provider)
You can not put the render of component outside of your ContextProvider.
Check this link:
https://codesandbox.io/s/busy-curran-pbz6p?file=/src/App.tsx:0-834

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/

React app confusion setting state of nested child component

I'm an embedded developer who is new to React and am struggling a bit with the behaviour of child components and nested child components.
I understand that for any component to be re-rendered, the state must change. I am using an example of a menu component that has an item component within. When some global level event happens, I want to change the text displayed by the item components.
Here is a fiddle that shows some code that I would expect to work:
https://codesandbox.io/s/dark-rain-8mfsp?file=/src/App.tsx
On clicking the div, the menu's setText function gets called, which calls into the item component, setting the state. This state is used in the render function of the item component, so I would expect both item and menu to be re-rendered.
Instead I get an error saying that I can't set the state of an object that hasn't yet been mounted. I would have thought it had been mounted..
Perhaps the way I have linked the declared components with those in the render functions by calling this.componentname.render() is the issue - but how else could that be done?
Thanks in advance!
Here is a working version of your sandbox.
https://codesandbox.io/s/lucid-bird-qecj0?file=/src/App.tsx:0-899
I see that you are new to react. I would suggest you use hooks instead of class components.

React - setting focus on body element / understanding refs

So I'm trying to understand how to move focus when a new page loads in my application. This question came to my mind: what could I do if I want to focus on some element that is somewhere outside of my component. It seems to me that everywhere they write about the focus it's always used with refs. You can pass ref to a child. What if I want to focus on element to reset the focus on the page when a link is clicked and new page component is loaded? Or if I want to make skip link component higher in the tree and focus on a header in element? I have a lot of components, it doesn't seem a great idea to pass refs down through several components.
I feel like I'm missing something.
I'm interested about this because I'm learning about accessibility and how to make possible to navigate page only with keyboard.
what could I do if I want to focus on some element that is somewhere
outside of my component.
What if I want to focus on element to reset the focus on the page when
a link is clicked and new page component is loaded?
You can just pass callback of focus handler into your inner component and call it when you want.

Resources