I have a TabView component that has multiple tabs containing components. These components have entire hierarchies of other components. How could I know from any child component nested arbitrarily deep in one of these hierarchies whether or not it's parent tab is in focus in the TabView?
Preferably, I would want to implement this similar to react-navigation's withNavigationFocus (or an equivalent hook) so that any component can know if it's in tab focus without having to pass props down the chain of components. I'm thinking you could have a TabViewContext that components can register themselves as focus listeners to by doing a useContext. The TabViewContext would be provided by the TabView and the TabView would be responsible for determining what registered listeners are in focus when tabs change. My dilemma is I don't know how the TabView could determine efficiently what nested child components come into focus when the tab changes. Any ideas?
In case the other parent tabs are hidden, you could test for visibility in plain JS, rather than have a much more complex solution...
Checkout this answer on how to do this.
So components that care about the visibility of their parent tab could use a ref for their own DOM elements and test whether they're visible or not. You could build this into a simple helper function or a hook
EDIT:
I'd suggest going with something like this:
Each Tab will provide a context with method for any descendant to register a callback that will be called when the Tab is hidden. The TabView can pass a "isVisible" prop to each tab (if it doesn't already), so Tab can know when its display changes.
When a Tab changes from visible to hidden. All registered callbacks will be called.
I would of course write a hook or a helper function to create this TabVisibilty context so each Tab component can use it in a reusable manner.
Related
What is the better practice for handling page scroll event in react?
A. addEventListener() in all components need page scroll event
B. Create a component as the wrapper of the page, and use onScroll to handle the event
C. Any other better approaches?
If you want to observe whether is an element in screen, Intersection Observer API can be used also.
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.
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.
I have a Tooltip component that when hovered displays a simple tooltip.
When you mouseLeave the component, a setTimeout fires, and when it ends, the tooltip is closed (setState({ open: false })).
Now I'd like to add a behavior to reflect the one of the native OS tooltips:
When you mouseLeave a tooltip, but instantly mouseEnter a different tooltip, the previous tooltip is instantly closed, and the new one gets opened.
To do so, I need to have a shared state between all the instances of Tooltip component. I could use Redux but it seems a bit overkill for a so simple task (I'd need a container that interacts with the store and makes an action and a property available).
Are there simpler solutions?
The best way to share information between ReactComponent is the Flux architecture. Redux is one of them.
A more simple option is to use the browser native storage used to store temporary information : it is similar to global variable but with particular scope and duration definitions.
Move the shared state into the state of the parent component of all Tooltips, have this parent define a method setWhatever to set the value, and pass this method to Tooltip components via a property. This way, children can call their setWhatever property, which is really the one of their parent, when they need to change the state.
I've designed a pretty simple responsive layout (be sure to open link with Chrome) and now I'm trying to implement it in React. I've attached some screenshots of the layout as well.
This app is supposed to be the typical tab/nav app, but due to the responsive layout, the view hierarchy is pretty awkward to work with in React.
I've built a React component called Layout to abstract away all the layout stuff. Layout also has props for renderLeft, renderRight, title, and onTab. Layout's children are then rendered into the content block.
The easy solution would be to make Layout a child of the current view and render whatever you want. However, this is going to mess up some animations I had in mind. I want to have a CSSTransitionGroup element wrapped around the tabbar, the title, and the left and right buttons animating them as they change. Thus, the Layout element must remain the same between the views else a new CSSTransitionGroup element will be rendered for each view which isn't good.
So now the problem is that I have a Layout component with a view rendered as its child (but sort of as sibling with respect to the App component), but the view needs to specify renderLeft, renderRight and title for the Layout which is its parent! For example, in the top-level App component, the render function may look like the following, and I need some way of setting Layout's renderLeft from the View.
render() {
return (
<Layout renderLeft={??}>
<View setRenderLeft={??}/>
<Layout/>
)
}
The only thing I've thought of so far seems totally like the wrong way of doing it:
In the top-level App component, have a state variables for renderLeft, renderRight, and title and App passes those to the Layout props. Now for the view, pass some functions like setRenderLeft, setRenderRight, and setTitle which will change the App state and thus change the Layout. We can thus call these functions in componentWillMount for each view.
This just seems like a total hack and seems to break the whole idea of one-directional-data-flow. However, I'm not sure how else to do it! Are there any more proper ways of doing this? I'm reminded of the concept of delegation when building iOS apps, but thats very OOP and not very FP.
Any ideas?
Your question is a little difficult to tell exactly what the issue is, however if I were you I would read up on https://facebook.github.io/react/tips/communicate-between-components.html
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.
You want to either have the siblings talk to the parent and communicate there, or at the global level.
Hope this helps.