-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How Should Refs Work? #3234
Comments
Another one that I've been thinking about is "parent-based refs". You could treat refs similar to context and assign it a unique key that bubbles upwards through the parent hierarchy and everyone in the hierarchy gets access to it. Effectively reversed context. Which is useful for other things too: https://github.com/reactjs/react-future/tree/master/04%20-%20Layout var DIV = new Symbol();
class Container {
componentDidMount() {
var myDiv = this.refs[DIV];
...
}
render() {
return <Something><div ref={DIV}>{this.props.children}</div></Something>;
}
} This should work for most cases but it has the possibility of screwing you up when they're nested: class Something {
render() {
if (stopRecursion) return this.props.children;
return <Container>{this.props.children}</Container>;
}
} It would provide a way to identify upwards signals such as this proposal: Anyway... Just an idea to spin-off other ideas. |
As I kind-of-mentioned in #3228, I suspect part of the answer is:
PS. That's obviously not the complete story, but it seems to me that refs for life-cycle events might not be the right way to go. |
I'm actually using a similar pattern in the next version of React DnD for attaching nodes to the higher-order component that binds drag and drop events. class Box extends Component {
static propTypes = {
dragPreviewRef: PropTypes.func.isRequired,
dragSourceRef: PropTypes.func.isRequired
};
render() {
const { dragSourceRef, dragPreviewRef } = this.props;
// Specify draggable node and drag preview node
// by using refs provided by higher-order component.
return (
<div ref={dragPreviewRef} className='draggable'>
<div ref={dragSourceRef} className='dragHandle' />
Drag me by the handle
</div>
);
}
}
export default configureDragDrop(Box, {
configure: (register) =>
register.dragSource(ItemTypes.BOX, boxSource),
collect: (connect, monitor, dragSourceId) => ({
// Refs are provided by higher-order component:
dragPreviewRef: connect.dragSourcePreview(dragSourceId),
dragSourceRef: connect.dragSource(dragSourceId)
})
}); I've come to really like this API because it provides flexibility to compose refs: function joinRefs(refA, refB) {
return function (instance) {
refA(instance);
refB(instance);
};
}
class Card {
render() {
const { caption, dragSourceRef, dropTargetRef } = this.props;
return (
<div ref={joinRefs(dragSourceRef, dropTargetRef)}>
{caption}
</div>
);
}
} Also I can always do it more manually for more tricky use cases (such as specifying a custom class Box extends Component {
componentDidMount() {
const dragPreview = new Image();
dragPreview.onLoad = () => this.props.dragPreviewRef(dragPreview);
dragPreview.src = 'http://image.jpg';
}
render() {
const { dragSourceRef } = this.props;
return (
<div className='draggable'>
<div ref={dragSourceRef} className='dragHandle' />
Drag me by the handle
</div>
);
}
} |
I have some limitation with the current ref function. class MyComponent extends React.Component {
state = { open: false }
ddc = DropDownController(open => this._onChange(open));
_onChange(open) {
this.setState({ open });
}
render() {
return (
<div>
<button ref={this.ddc.openButtonRef}>+</button>
{this.state.open &&
<div ref={this.ddc.dropDownRef}>....</div>}
</div>
}
} The controller manually creates event handlers and the dropdown is closed if a click event happen outside of the dropdown. One solution could be that the ref function is invoqued with |
hm. I'm currently working on view recycling which allow us more efficient use of resources in long lists or tabs that share similar behaviors. One of the interesting qualities of that problem is that instances are no longer necessarily tied to the state of a component. I'm not sure what that means for this particular problem yet but I suspect that relying on instance identity here might be problematic. Maybe not though. |
Spinoff discussion of #1373, #3128 and #3228.
We're pretty sure that we need to change the current way refs work (see above). However, the new ref callbacks are also not ideal because it relies on some imperative code and suffers from timing issues like all imperative life-cycles. It is also not very convenient without arrow functions. Even with arrow functions it might suffer from performance issues.
A few things refs tries to solve:
The text was updated successfully, but these errors were encountered: