Reactjs - How to see method definition in props with VSCode - reactjs

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.

Related

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.

Want to modify props but i cant find them

I'm making some modifications on this app by only understanding the syntax, i don't understand very much how it is built.
If someone could help me understand how the props get passed to this component that would be nice (i want to modify the props) React file .
The props are being passed at line 26
{childrenLinks.map((child, index) => {
return <DropDownChild child={child} key={`${child.url}-${index}`} />;
})}
childrenLink is also coming from a prop called linked passed from the parent component that calls SideMenuDropDown component.
I actually found it, it gets populated from the backend there is a file index.go in /pkg/api that does it

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={}/>.

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

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.

How to envoke a method on a react component (Amcharts-React)

Is there a way to evoke a method on a chart. Such as:
chart.zoomOut()
I'm struggling to find a handle for the chart object.
To render the chart i use:
<AmCharts ref={`chart_${this.props.tileid}`} {...this.chart} dataProvider={this.props.data} />
https://github.com/amcharts/amcharts3-react
I tried to inspect the element to see if I can access these methods through:
ch = this.refs[`chart_${this.props.tileid}`]
However in the 'ch' object I can not seem to find any of the methods mentioned in:
https://docs.amcharts.com/3/javascriptcharts/AmSerialChart#zoomOut
How would one reference a element to evoke a method on it?
The amchart3-react component sets the chart as a state. Thus the method can be evoked by calling:
this.refs.chartref.state.chart.zoomOut();
You will have to talk to the maintainers of amCharts3-react. The wrapper component library could have defined the component to accept as property an event-handler that is called when the wrapper's componentDidMount method has been called, so that the event-handler can grab an instance of an object that the wrapper component is a container of.
Example:
// Note, this is just a hypothetical property. It will not actually do anything
// when applied to your code.
<AmCharts onChartRendered={chart => this._amChart = chart } {...props} />
But it seems like the author of the wrapper did not define the component to accept any such property, and therefore there isn't any way for you to invoke any methods from amCharts.

Resources