Detecting click outside React component and single state for hover - reactjs

I have made a navbar, which holds a searchbar, and 3 icons.
On clicking these icons, a modal is rendered.
I wanted help with two things.
Closing the modals on outside clicks!, and
The hover element is slow because it has three states, every time it is called it re-renders the code from bottom to top. I wanted the hover to have one state assigned to one parent element. But on doing that, the hover effect for all three buttons gets activated at the same time.
Code is up on : https://codesandbox.io/s/unruffled-snowflake-he95w
Please feel free to edit the code and pass me the edited fork.
I have tried handleBlur, passing an event, and eventListener.
https://codesandbox.io/s/unruffled-snowflake-he95w
Expected - Modal rendered on screen should get disappeared on clicking outside the modal.
P.S - semantic UI icons are not rendering, but they are there. They will activate if you hover over them.
Credits - SVG close icon problem solved by Drew Reese.

Ah, I see. Your ToolBar is the controlling component, i.e. the state about whether or not each toolbar item is open is stored there. You need to pass a close handler to the children components so when a "close" button is clicked it is calling the callback the parent passed in.
Here is a fork of your sandbox where I pass in an onCloseClick callback to the calendar/picker thing that simply toggles that state value back to false to close it. The picker then just assigns that callback as its onClick handler for the contaning for the close button.
You can apply the same logic to the other two components.
Note: since the icons aren't rendering for me either I added some text to the buttons so they are easier to find/see.

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.

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

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

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.

Prevent React hook from being called when state changes

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.

React swallows onClick event on li element

I'm using react-window to optimize a custom dropdown menu component. The dropdown's menu uses the List component from react-window to render a ul, and the item component passed to the List renders an li element with an onClick handler assigned (to close the menu and pick an item). The dropdown component worked fine before I used react-window, but after switching, the onClick handler does not fire the first time each li element is clicked.
Investigating the li in Chrome's dev tools revealed that after the li node is first mounted, React attaches an noop event handler to the node's onclick property, apparently due to some iOS Safari bug (here). After clicking the node once, this goes away and my onClick handler fires properly.
If I change the event to onMouseUp, it works fine, but I shouldn't have to do that; I should be able to use onClick and have it fire reliably.
I'd like to file a bug report on this, but I'm not entirely sure if it's React's fault or react-window's fault. I looked through the source of react-window and it doesn't seem to do anything strange to render the item component; it just uses createElement. Obviously onClick events work for some elements, including my li elements before I moved to react-window...somehow the noop event handler wasn't affecting them beforehand.
Is anyone else familiar with this particular iOS workaround and why it's suddenly breaking my event handlers?

Resources