I'm writing the code in CoffeeScript since I've been writing React with it.
Here is the basic structure.
{ div, input } = React.DOM Outer = React.createClass render: -> div { id: 'myApp' }, Inner() Inner = React.createClass render: -> input { id: 'myInput', ref: 'myInput' }
I have a toggle
method on my Outer class which is triggered by pressing a shortcut. It toggles the visibility of my app.
When my app is toggled from hidden to shown, I want to focus on the input.
Now the toggle methods look more or less like this:
Outer = React.createClass render: -> ...... hide: -> @setState { visible: no } show: -> @setState { visible: yes } $('#myInput').focus() # jQuery # I want to do something like # @refs.myInput.getDOMNode().focus() # But @refs here is empty, it doesn't contain the refs in Inner toggle: -> if @state.visible @hide() else @show()
How do I do this then?
In child component, we create Refs by using React. createRef() and then attached to React elements via the ref attribute. // EXPLANATION: a reference to the node becomes accessible at the current attribute of the ref. In the parent component, we can get a reference to the Input component and call its focus() method.
The forwardRef hooks allows React users to pass refs to child components. The ref can be created and referenced with useRef or createRef and then passed in a parent component. Using forwardRef instead of useRef is useful when a ref needs to be accessed in a parent component.
You may access the child state by passing a callback to the child component. Now if you click the button in the child component, you will execute the function passed from the parent and have access to the child component's state variables.
To pass data from a child component to its parent, we can call a parent function from the child component with arguments. The parent function can be passed down to the child as a prop, and the function arguments are the data that the parent will receive.
Accessing the refs
of a child breaks encapsulation since refs
are not considered part of a component's API. Instead you should expose a function on Inner
that can be called by a parent component, calling it focus
might make sense.
Also, focus the element in componentDidUpdate
to ensure rendering is complete:
{ div, input } = React.DOM Outer = React.createClass render: -> div { id: 'myApp' }, Inner({ref: 'inner'}) componentDidUpdate: (prevProps, prevState) -> # Focus if `visible` went from false to true if (@state.visible && !prevState.visible) @refs.inner.focus() hide: -> @setState { visible: no } show: -> @setState { visible: yes } toggle: -> if @state.visible @hide() else @show() Inner = React.createClass focus: -> @refs.myInput.getDOMNode().focus() render: -> input { id: 'myInput', ref: 'myInput' }
You can chain refs, so if you pull an element by ref, you can grab refs inside that element:
Defining your Outer
class as Outer = React.createClass render: -> div { id: 'myApp' }, Inner {ref: 'inner'}
would let you then grab the input with @refs.inner.refs.myInput.getDOMNode()
to call focus
on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With