How can I focus on a react-select component at will? - reactjs

Using react-select v2, I want to show and focus on the Select element when the user hits a certain key. Following are some things I've tried or paths I've gone down.
When I set a ref to the Select element and try to call .focus on it, it says no focus function is found. Perhaps I should somehow get a child element of it and then call focus on that?
There doesn't seem to be any prop I can pass that will trigger a focus function. There is an openOnFocus but not a focusOnOpen. The only thing I can think of would be to enable autoFocus and then somehow trigger a remount but there doesn't seem to be a simple way to do this and it feels hacky. Alternatively, I could enable just create the Select component each time the key is pressed instead of showing it, then unmount it instead of hiding it.
How can I properly get the react-select element to gain focus when I want it to?
I'm using a wrapper component around my component. Here's the render method for my wrapper:
render() {
return (
<Select
options={this.props.options}
value={this.state.value}
ref={this.selectRef}
/>
);
}
And here's where I'm calling that wrapper:
<Wrapper
options={this.props.labelOptions}
ref={this.wrapperRef}
/>
I then try calling focus using either this.dropdownNode.focus() or this.dropdownNode.current.focus() and both say no focus method is found.

Because you're wrapping the Select component, you can't call Select's .focus() function from the ref you're giving to the wrapper. Since ref is a special kind of prop, the ref for that wrapper is only referring to Wrapper itself, not the component it wraps (Select).
To access the actual Select component's ref, you have to pass a ref down to it as a prop with a different, non-magic name, like innerRef (react-select code actually gives a good example of this as it's accessing the actual input element and focusing on that).
Here's the change that fixed it. Here is the wrapper component where Select is actually used (and it's taking in the ref passed to it):
render() {
return (
<Select
options={this.props.options}
value={this.state.value}
ref={this.props.innerRef}
/>
);
}
And here's the component that's calling that wrapper. In the constructor I'm creating the ref with this.selectRef = React.createRef() then I pass it in as a prop in this render method:
<Wrapper
options={this.props.labelOptions}
innerRef={this.selectRef}
/>
Then I can call focus on the Select component itself by running this.selectRef.current.focus() anywhere I want to.
Notes: Thanks to BoyWithSilverWings answer. This question pertains to React 16.3. There is also a new React.ForwardRefs method but this way seems simpler to me.

Related

Reactjs - How to see method definition in props with VSCode

As I read here, one way in reactjs to reuse code is to put it in a "container" component, then pass it down to its child via props. Cool.
Problems rise to me when, in my IDE (VSCode), I need to go to the method/property implementation: if code is imported via oldSchool "import", then everything works by "ctrl+clicking" the method name; but if I'm inspecting a method/property passed via props by the parent component, then "ctrl+click" on the method name is useless:
<div onClick={props.**methodFromParent**()}>Click me</div>
That's pretty obvuios, because there are no refs in my child code about the parent component itself (they get composited in another component ad-hoc). So is there a way to have this feature back? Because is very usefull to me.
Can't be possible.
If you define a method in the parent and pass it to the child you are not passing the mothod. What you actually are passing is a reference to a function and the child executes that function.
Like you mentioned it is possible to reuse code that way. The child doesn't know what method will be passed. It is not a static binding. So the IDE can't know either.
You could have something like:
// Parent component
const add = (a,b) => return a+b;
const sub = (a,b) => return a-b;
return ( <>
<child num=4 action={add}>
<child num=7 action={sub}>
</>);
// Child component
return (
<div>The result is {props.action(10, props.num)}</div>
);
As you see the property "action" doesn't relate to any particular method on the parent, it is just a property and the IDE can't show you a definition.

Can you explain this react native code (strange arrow function in render method)?

So this is some React Native code from a textbook that I'm going through, specifically it is from the render method of App.js. Of course the /* ...*/ would be filled in with actual code but it's irrelevant to my question.
<MeasureLayout>
{layout => (
<KeyboardState layout={layout}>
{keyboardInfo => /* … */}
</KeyboardState>
)}
</MeasureLayout>
What I don't understand is what is happening with {layout => (.... So I take it that layout is an arrow function that returns this keyboardState component. So how does layout then pass itself into keyboardState's layout prop at this part <KeyboardState layout={layout}>? And why would I want to do that exactly? This whole part here is really baffling me.
React components have props and children properties. The children property is usually a React node, but it can also be a function that returns a React node.
So how does layout then pass itself into keyboardState's layout prop at this part ?
The MeasureLayout component was created so that its children property was defined as a function instead of a React node.
And why would I want to do that exactly?
For dependency injection and as a pattern that allows for a more declarative style of programming with class-based components.
Some more in depth reading:
Topic: Functions as children
https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9
https://codedaily.io/tutorials/6/Using-Functions-as-Children-and-Render-Props-in-React-Components
See that {} inside render method is used for some javascript statements.
For eg.
<Text>
{personFirstNam +" " +personLastName}
</Text>
But now that in your code there is again JSX elements inside {}, it is used inside unnamed function.
i.e.
{layout => (
...// here you can use JSX element which will be returned into render method for UI.
)}
alternatively, if you want some operations there,
{layout =>{
let extractData = fromSomeWhere;
let calculatePosition = getPosition();
return (<KeyboardState layout={layout}>
{keyboardInfo => /* … */}
</KeyboardState>)
}}
All of these was to just do some JS statement executions/operations inside one JSX element.
The <MeasureLayout> is passing an argument to its children as a function. and to recieve it an arrow function is used.
so, basically the code of <MeasureLayout> will be,
function MesauseLayout(props){
//Do things
// layout = some result.
return <div>{props.children(layout)}</div>
}
So, in order to receive this the child will have to be inside a function that accepts this value. So, an arrow function is used to receive this value.
<MeasureLayout>
{layout => (
<KeyboardState layout={layout}>
{keyboardInfo => /* … */}
</KeyboardState>
)}
</MeasureLayout>
But in my opinion, using a Context/Provider with a hook will be a better option if that is possible. This is generally only used in extreme cases. There is also another option to use React.cloneElement and passing additional props. But there are tradeoffs if you have to choose between these two. Plus, There is a concept called render props which is commonly used in new libraries.

cannot render a complex React Element in order to replace a DOM element by id

I am a beginner with react so please excuse me if this question does not make sense.
I have a complex div element in the html document with an id, it looks like this:
aaavote: I am comingChange My voteDelete Me
and it was originally created from rendering a react element that was returned from a component, like this:
let content = visitors_list.map((visitor) =>
)
{content} was returned from the react component.
At some stage I need to replace that div (with id="MyDiv2") with a different content.
I have a function that creates this new "content" exactly the same way I created the original one, however, now instead of return it from the component and have react do the rendering, I need to do it manually and call:
document.getElementById("MyDiv2").innerHTML = something
I cannot just pass content as something because : component is an array of [object Object]
I cannot pass it as a json structure because JSON.stringify(content) gives me:
[{"type":"div","key":"1","ref":null,"props":{"className":"flex-no-shrink w-full md:w-1/4 md:px-3","children":{"key":null,"ref":null,"props":{"visitor":{"id":"1","name":"aaa","vote":0,"imageUrl":"http://www.stone-guitar-picks.com/stoneguitarpicksshop/images/large/GP2046_LRG.JPG"}},"_owner":null,"_store":{}}},"_owner":null,"_store":{}}]
so I tried: ReactDOM.render(content, document.getElementById("MyDiv2"))
but ReactDOM.render does nothing, infact it breaks and exists the function.
I also tried using React.createElement(content) - also did not work...
How can I solve this problem. the only solution that I found to work is forcing the refreshing of the page which I do not want to do.
Dont try to handle the dom manually, react does this for you!, imagine you have your component MyInput that renders an input with some characteristics that may be passed by properties as well, then you could just change your component props and react will change your component automatically. i'll try to post a hardcoded example:
const myComp = ({text, visible}) = return (
<input text={text} visibility={visible}>
)
then, when you change your component text it will render it automatically.

How to access ref or focus to an material-ui/KeyboardDatePicker?

I try change the page focus to a single Datepicker component from material-ui (https://material-ui-pickers.dev/api/KeyboardDatePicker).
There, they clearly stated that any ref props will be forwarded to root component (whatever it is). So I assume it will behave like any typical input. But any attempt to access ref will throw an error: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
// THIS DOESN'T
<KeyboardDatePicker
clearable
ref={this.inputs.birth_date}
value={this.state.birth_date}
onChange={this.handleChangeDate}
/>
// THIS WORKS
<input ref={this.inputs.birth_date} />
This appears to be a bug in the library. Fix is available in v4.0.0-alpha.4
https://github.com/mui-org/material-ui-pickers/issues/1303

React.forwardRef is already possible without it, so what's the use of it?

I'm confused on the point of React.forwardRef. As explained in its documentation, I understand that its main use is for a Parent Component to gain access to DOM elements of the Child Component. But I can already do that without even having to use it.
Here is a code example that you can plug into CodeSandbox and see that it works:
import React, {useRef, useEffect} from "react";
import "./styles.css";
const ChildComponent = (props) => {
useEffect( ()=> {
props.callbackFunction()
})
return(
<div ref={props.fRef}>
{"hello"}
</div>
)
}
export default function App() {
const callbackFunction = () => {
console.log("The parent is now holding the forwarded ref to the child div: ")
console.log(forwardedRef)
}
const forwardedRef = useRef(null)
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<ChildComponent name="gravy" callbackFunction={callbackFunction} fRef={forwardedRef}/>
</div>
);
}
Or here's the embed of this example. Honestly, I'm kind of new to this and I don't know exactly how embeds work and whether someone fiddling with the embed changes my original Sandbox or not, so I was hesitant to put it. But here it is.
Example Forwarding Ref
In the example, the parent App() component successfully passes a ref to the child which the child attaches to its rendered div. After it renders, it calls a callback function to the parent. The parent then does a console log where it proves that its forwarded ref now has a hold of the child's div. And this is all done without React.forwardRef.
So what then is the use for React.forwardRef?
You're absolutely right that you can do what you've described. The downside is that you're forced to expose an API (ie: the fRef prop) for it to work. Not a huge deal if you're a solo developer building an app, but it can be more problematic eg. if you're maintaining an open-source library with a public API.
In that case, consumers of the library won't have access to the internals of a component, meaning you'd have to expose it for them somehow. You could simply do what you're suggesting in your example and add a named prop. In fact, that's what libraries did before React 16.3. Not a huge deal, but you'd have to document it so people know how to use it. Ideally, you'd also want some kind of standard that everyone used so it wasn't confusing (many libraries used the innerRef naming convention), but there'd have to be some consensus around that. So all doable, but perhaps not the ideal solution.
Using forwardRef, passing a ref to a component just works as expected. The ref prop is already standardized in React, so you don't need to go look at docs to figure out how to pass the ref down or how it works. However, the approach you describe is totally fine and if it meets your needs, by all means go with that.
As mentioned in the docs , it's useful for highly reusable components, meaning components that tend to be used like regular HTML DOM elements.
This is useful for component libraries where you have lots of "leaf" components. You've probably used one like Material UI.
Example:
Let's say you're maintaining a component library.
You create a <Button/> and <Input/> component that maybe just adds some default styling.
Notice how these components literally are just like regular HTML DOM elements with extra steps.
If these components were made to be used like regular HTML DOM elements, then I expect all the props to be the same, including ref, no?
Wouldn't it be tedious if to get the button ref from your <Button/> component I'd have to get it through something like fRef or buttonRef ?
Same with your <Input/>, do I have to go to the documentation just to find out what ref to use and it's something like inputRef ? Now I have to memorize?
Getting the ref should be as simple as <Button ref={}/>
Problem
As you might know, ref will not get passed through props because, like key, it is handled differently by React.
Solution
React.forwardRef() solves this so I can use <Button ref={}/> or <Input ref={}/>.

Resources