I have a components hierarchy like this:
<parent>
<someWrapper1>
<child>
<child>
<someWrapper2>
<child>
<child>
Each child component handles a bunch of mouse events on it's own where some are D3 wrappers managing onDragStart and onClick mouse events.
I am looking for a way to disable all mouse events in the <someWrapper1/>, <someWrapper2/> components, as well as in the <child/> components, based on the parent's component state.
One solution, would be to pass the prop of disable to the wrapper components, and to also pass those down to each child and then into
each handler to disable or enable mouse events. I want to avoid this as it will be hard to maintain.
I am looking for a nicer solution where I can disable all mouse events in all components from the parent component.
Thanks!
If I understand correctly, you're looking to disable mouse events on specific sub-trees of your DOM. In that case, you could use the CSS pointer-events: none; rule to achieve this.
For example, to restrict mouse events on an element/component and it's children, you could create a style object with a pointer-events key and none value, and apply this to <someWrapper1> components to dynamically enable/disable mouse events on those components (and their descendants):
/* Your components render method */
render() {
/* Acquire the disableEvents value from state, etc */
const disableEvents = true;
/* Dynamically compute style for wrapper components
to control mouse interactivity */
const wrapperStyle = {
"pointer-events": disableEvents ? "none" : "unset"
};
/* Apply dynamic styles to wrappers. When disableEvents
is true, mouse events will be disabled on someWrapper1
and child descendants */
return (<parent>
<someWrapper1 style={wrapperStyle}>
<child />
<child />
</someWrapper1>
<someWrapper1 style={wrapperStyle}>
<child />
<child />
</someWrapper1>
</parent>)
}
Related
I'm currently working with Fluent UI to create a web app, and in this app I'm attempting to create a Fluent UI Dialog with a custom component that contains a Fluent UI ComboBox inside of it. I'm calling ReactDOM.createPortal on return from the render method inside of my custom React object. Upon first use of the Dialog my ComboBox functions as expected, i.e. the dropdown shows properly and it allows me to select and interact with my page as intended. However, when closing the Dialog after having already interacted with the ComboBox, upon re-opening the Dialog the ComboBox no longer displays the dropdown (although I can see the options are still there, just somewhere in the background). I've tried adjusting the zIndex of the ComboBox, it's container, etc. with no luck. I'm starting to think that it's an issue with ReactDOM.createPortal whenever the component is re-rendered after having been interacted with in a previous render, and figured I'd see if anyone has ever tried to do something similar. Thanks so much in advance!
render() {
const {options, changeOptions} = this.store;
return (
<>
{!!this.item && buttonTexts.length && ReactDOM.createPortal(
<ComboBox
label='Title'
selectedKey={changeOptions}
onChange={this.changeOptionDisplaying}
options={options.map(text => ({ key: text, text }))}
/>,
this.item
)}
<div ref={this.setRef} dangerouslySetInnerHTML={{ __html: this.props.htmlString}} />
</>
)
}
// this.item is an HTMLDivElement
I am writing an editor where I would like to be notified for any change into the
document. So I created a tree of components where each node report to the parent
via a onChange(..) callback:
// Pseudo structure.
Root {
const [changed, setChanged] = useState(true)
function onChange(..) {
setChanged(true);
}
return (
<App>
<Status saved={!changed} />
<Editor onChange={onChange}>
<Text onChange={onChange} />
<Image onChange={onChange} />
</Editor>
</App>
);
}
Now I have to create a <Table> component where each cell is an editable input
that trigger the onChange callback. Because of the useState in Root, each
time we change one letter in the table, the whole structure is rendered.
But the rendering cause a loose of the focus, which is admittedly annoying to
type a text. My current solution is to save the current cell via useMemo in my
new Table component and request the focus when the component is rendered.
However, I still loose the caret position and I have the feeling this is a hacky
way of working (That's why I am reaching you).
How can I notify a change and update the state of my Root without losing the
focus from one input ?
Thanks
My suggestion
Keep stateless components as child.
Use keys for each cell to avoid unnecessary rerendering from parent.
I am using redux to change style of my custom NavBar component. My NavBar is not part of Router neither scenes, I introduce them in direct scene JSX. Example JSX from my scene component:
<View style={{ flex: 1 }}>
<NavigationBar /> <--- My custom NavBar
{ this.renderScreen() }
<Tabulator
tabs={TABS}
style={styles.navbar}
listenTo='screen'
/>
</View>
In the second scene I have a ScrollView which is dispatching actions when I scroll the view. For an example, I am dispatching opacity of the NavBar while you scroll down and change its title after a certain y value. The problem is, when I scroll the view and before it can stop I go back from the second scene to the first one, the ScrollView did not yet stopped scrolling so it dispatches few more actions.
Is there a way to disable the scene?
I have noticed that this gets called while the scene is alive during the scene change animation until componentWillUnmount() gets called.
I tried to put a reducer into the router and dispatching an action that the scene switching is in progress. I check if the action type is anything else than REACT_NATIVE_ROUTER_FLUX_FOCUS then the changing is in progress. so while it is true the action changing the NavBar is ignored, but this sets false before it gets to unmounting.
I am implementing a small react component called react-hover in it's V2 version.
This lib just simply enable user to define their trigger and hover component and make the hover component appear when mouse hover on trigger component.
<ReactHover
options={optionsCursorTrueWithMargin}>
<ReactHover.Trigger>
<TriggerComponent />
</ReactHover.Trigger>
<ReactHover.Hover>
<HoverComponent />
</ReactHover.Hover>
</ReactHover>
Now I am facing an issue of passing the onMouseHover events to the children component in tigger component:
render () {
return (
<div
onMouseOver={this.onMouseOver.bind(this)}
onMouseOut={this.onMouseOut.bind(this)}
onMouseMove={this.onMouseMove.bind(this)}
onTouchStart={this.onTouchStart.bind(this)}
onTouchEnd={this.onTouchEnd.bind(this)}
>
{this.props.children.props.children}
</div>
)
}
Because only the children component can tigger the hover component, but in above implementation, it is binding the listeners to the parent div, so I met the issue that parent div's css width is more than the childen's width, so when mouse is on the div ( not in the children) the hover component show up. But I cannot control the children component's inner code as it is passed in as children.
I am just wondering how to tackle this issue?
The example code is here.
The place where bind the mouse event is here
Just wondering what's the solution for this?
how to bind those events to the children component when cannot put code in children component.
Below is showing when mouse outside of trigger component still can trigger the hover component.
Just resolved by add ref to the container and retrieve Children's width:
let childStyles = this.refs.triggerContainer.children[0].style
and apply to the current parent container.
check this code
I'm using the Material-UI Tabs component in my ReactJS app.
I'm handling the onTouchTap event of the Tabs component. I'd like to pass the currently selected tab back as a parameter to the event handler.
Is this possible?
So something like this
<Tabs onChange={props.onChangePosition}
onTouchTap={e => {/* What */}>
I know that the onChange handler returns it, but I'd like to use onTouchTap in this instance.
Yes, this can be done. You need to capture a "ref" to your Tabs control, and then call getSelectedIndex() on it, inside your onTouchTap. getSelectedIndex is somewhat internal, so it has an unexpected method signature in that you must also pass it in its own props.
<Tabs
ref={ref => (this.tabs = ref)}
onTouchTap={(e) => console.log(this.tabs.getSelectedIndex(this.tabs.props))}
>
...