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

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.

Related

Get a JSX's elements class name after load and on change

I'm a bit lost learning React here.
I'm trying to get the class name of an element so I can inject an inline color depending on that class name. For example, if the element below has the class 'Active'.
<li className="active" >
I was experimenting trying to use the onChange event to see if it worked but I can't seem to fetch and print anything in the console. I assumed the event would have triggered after load and when the clase name changes, doesn't seem the case.
<li className="active" onChange={(e)=> {(console.log(e.target.className))}}
I've read a bit about React refs but it seems too much for such a simple thing. What am I missing here?
You don't need to use onChange event. You probably want to use the document object wherever you want to change the style of an element.
document.getElementsByClassName("Active")[0].style.color = '#fff';
You can use it in a function and trigger it wherever you want, or just simply put it inside useEffect hook to execute on component mount.

Are there any benefits of calling an SFC function within the render method?

I am working with the react-gsap library, and want to encapsulate specific <Tween> instances that do not need any props, because they are occuring multiple times in the same way.
Lets take a simple example of an instance, that doesn't need any props or state at all. Let's say this line
<Tween
to={{opacity: 0}}
duration={5}
/>
occurs really often in our code base, and we want to abstract it.
My first idea was to just create an SFC for that:
const HideTween = () => (
<Tween to={{ opacity: 0 }} duration={5} />
);
// and then ...
<HideTween />
but that seems not to work at all. The Tweens are simply not showing any effect.
I then came up with another idea (which i personally dislike) to just call the SFC. Instead of <HideTween /> , we now have
{HideTween()}
and voila, it works...
I am specifically curious now, why my first idea did not work at all. The question is not aimed into the gsap library directly, but more of a general form: Where, when and how can such an approach (of abstracting parts of your render into own functions) fail? If it is the library, how does it even achieve such a behaviour?
And why does it seem to work, when i call the function directly (i know this is kind of a bad approach)? Without any state or props present,
shouldn't <HideTween /> have the same effect on every render as {HideTween()}?
EDIT
Here is a minimal example
Exchange <Tweens /> in line 38 with the content of the Tweens SFC, and you will see the animation again.
You can share the same elements between different render methods by creating them ahead of the render cycle as you tried to do:
const HideTween = <Tween to={{ opacity: 0 }} duration={5} />
and then directly using the element (not instance) in the render methods:
<Timeline>
{HideTween}
</Timeline>
<Component /> is JSX sugar for creating an element of a react component. So your first idea didn't work as it would return an element returning an element of a Tween and not directly the Tween element. For usual DOM rendering this will work as expected, though. The second example works as you get the Tween element this way, but you're right to dislike it as it simply adds an unnecessary indirection.
Doing it this way you might think that react will reuse the same instance of the component in different places, but it will actually instantiate the component anew for each usage. Here is an example:
https://stackblitz.com/edit/react-rzq5q5?file=index.js
I assume this is intentional as sharing the same instance of a component seems to be quite a rare use case and with stateful components the state would be shared as well synchronising components in different parts of the app (which could end up being quite confusing).
Also check out this article on the difference between components, elements and instances (instances will be created by react for you): React Components, Elements, and Instances
Here I've set up a simple example trying out a few things: Example
In your Tween component:
class Tween extends React.Component {
static defaultProps = {
to: {opacity: 0},
duration: 5
}
...
}

React.js how to call child component method without using refs?

I have an unusual case. Let say, I have a form. When the user clicks the "save" button I need to trigger a component's method to convert draft.js content to HTML. Normally I just use refs to get access to child and call any method. But in my case draft component is inside render method of react-router v4 and appears only when URL match pattern.
This is a hindrance cuz when I define ref
<Match pattern={'/info'} render={(props)=> <Draft_Editor ref='editor' />} />
parent component doesn't have this 'editor' in refs. What can i do to call method on from parent ?
One way is as follows.
1) Find the DOM node for the parent element using:
var parentDOM = ReactDOM.findDOMNode(parentCompInstance);
2) Find the DOM node for the child element, using:
var childDOM = parentDOM.children[0]; // or something like this, depending on html hierarchy
3) Find the React component instance for that child DOM node, using the solution mentioned here: React - get React component from a child DOM element?
I found solution for my case. Unfortunate, the solution is using ref but it performs it with other approach. Instead of making this ref='editor' I did this ref={(draft) => this.aboutEditor = draft}. This editor will be available as this.aboutEditor.
When i operated with ref as string it did't works. But it works fine as callback function.

React 15.4.2 Cannot read property 'ref' of null

I try get access to method of child component.
It look like that:
1.Called method by ref name of component and then method
Form.js
this.ref.details.getDataFromComponent();
<Details
pointToShow={this.state.point}
ref="details"
/>
Details.js
getDataFromComponent() {
//do my stuff get state and connect to get data for component Details
}
All the time I have "Uncaught TypeError: Cannot read property 'ref' of null"
React 15.4.2
To access refs of a component, you need to use this.refs, not this.ref.
However, this does not seem to be the issue here, as the error clearly says that this is null when you are trying to access it. To determine why this is we need to see more of your code.
You should also look into defining refs using the ref callback attribute instead of the way you are doing it, as this syntax is no longer recommended and may be removed in future releases.
As Timo has mentioned to access an element using refs you should you should write this.refs...
According to the error you don't have access to this. Most probably you are calling this.ref.details.getDataFromComponent(); inside a method without access to this
For example you write :
callRef() {
this.ref.details.getDataFromComponent();
....
}
If so then you don't have an access to this there. You should bind your function with this.
You can either use arrow function to auto bind with this :
callRef = () => {
this.ref.details.getDataFromComponent();
....
}
Note: to use arrow function you need to use babel loader in your webpack configuration.
Or you can bind when calling the method.
For example you should call callRef() method inside jsx codes like this:
< ... onClick={this.callRef.bind(this)} />

Flow error on function added to prototype

we have a ton of components and many of them call a "register" function that, in turn, adds a method to the component's prototype. It has to do with translations. The method is simply 't(name:string):string'. It works great at runtime, but flow gives an error, such as <Button title={this.t('signIn')} /> propertyt. Property not found in class Welcome extends Component {
I get it, flow is a static type checker and that method is dynamically added. I'd rather not make a new class with a single function that all components have to derive from in order to satisfy flow.
What I'd like to be able to do is say "Flow, class Component from module React also has a 't' function". I tried messing with declare interface/module/class/function, but nothing fixed it. Any ideas?

Resources