Pass ag-grid data from child to parent - reactjs

New to react from angular
Receiving the error:
The above error occurred in the <div> component: in div
Consider adding an error boundary to your tree to customize error handling behavior.
I don't quite understand why div and what the error is talking about?
I am trying to click on a row and pass the values from row to parent.
In my top level parent component, I have a function that would set the value of the selected row and in the child, the selected row is pass to props.
Parent:
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
activeItem: []
}
this.setActiveItem = this.setActiveItem.bind(this)
}
setActiveItem = userSelect => {
this.setState({ activeItem: userSelect })
}
render(){
<Child activeItem={this.setActiveItem}/>
}
In my child, I use ag-grid using onRowClicked. The error is getting thrown in this.props.setActiveItem(event.data)
class Child extends React.Component {
constructor(props) {
super(props)
}
onRowClicked = event => {
//eslint-disable-next-line no-console
console.log('tester', event.data) //okay, shows data
this.props.setActiveItem(event.data) //not okay, throws error
}
grid = () => {
return (
<AgGridReact
columnDefs={this.state.columnDefs}
rowData={this.state.data}
onRowClicked={this.onRowClicked}
/>
)
}
render() {
if (this.state.data.length > 0) {
return <div className="ag-mod">{this.grid()}</div>
}
return <br />
}
}
//also here's the prop for child
Child.propTypes = {
setActiveItem: PropTypes.func
}

You are passing down setActiveItem from parent to child as activeItem.
<Child activeItem={this.setActiveItem}/>
So in child call it with the name you gave in when passing it down.
onRowClicked = event => {
//eslint-disable-next-line no-console
console.log('tester', event.data) //okay, shows data
this.props.activeItem(event.data) //not okay, throws error
}
Also, consider wrapping your components in an error boundary as the error mentioned. It helps. You can read about that here

Related

React.js - Pass data to parent method as a parameter from child

I am simply trying to pass a value back up to a parent component when I invoke a method in a child component.
I have a parent component called Job. It renders a child component called SummaryChart. When a bar on the barchart is clicked from within SummaryChart, I want it to tell Job which bar was clicked, and to open a modal.
Parent Component
class Job extends Component {
constructor(props)
{
super(props);
this.state = {
...
}
this.getSequenceView = this.getSequenceView.bind(this);
}
getSequenceView(config, event)
{
console.log(config.someData);
$('#help-modal').modal();
}
render()
{
return (
<SummaryChart
handleBarClick={() => this.getSequenceView(config, event)}
/>
);
}
Child Component
class SummaryChart extends Component {
constructor(props) {
super(props);
this.state = {
options: {
chart: {
events: {
dataPointSelection: function(event, chartContext, config) {
props.handleBarClick(config, event);
},
}
}
}
render() {
return (
...
);
}
}
I receive the following error when I click:
Uncaught ReferenceError: config is not defined
I'm thinking my error must lie in my parent component when I pass the prop to SummaryChart, but I don't know how else to tell the method to expect two arguments. Other examples have things like hard-coded props as arguments, but I want to use information from ApexCharts click events to pass back up to the parent.
You're missing the method argument in the child call.
<SummaryChart
handleBarClick={(config, event) => this.getSequenceView(config, event)}
/>

React.js - Cannot read property of undefined, even though context is bound (call parent method from child)

I am building a small app in React -- trying to call a function from my parent component Job when a bar from a bar chart (ApexCharts) is clicked in a child component SummaryChart.
Naturally, the way I have read to do this is to define a function in Job called getSequenceView, and pass it in a prop to Chart under the alias handleBarClick, then call this.props.handleBarClick from SummaryChart to invoke it in the parent.
Parent Component
class Job extends Component {
constructor(props)
{
super(props);
this.state = {
...
}
this.getSequenceView = this.getSequenceView.bind(this);
}
getSequenceView(config, event)
{
console.log(config.someData);
$('#help-modal').modal();
}
render()
{
return (
<SummaryChart
handleBarClick={this.getSequenceView}
/>
);
}
Child Component
class SummaryChart extends Component {
constructor(props) {
super(props);
this.state = {
options: {
chart: {
events: {
dataPointSelection: function(event, chartContext, config) {
this.props.handleBarClick();
},
}
}
}
render() {
return (
<Chart
options={this.state.options}
series={this.state.series}
type="bar"
width="100%"
/>
);
}
}
ApexCharts docs for handling events here!
I have a feeling that since I am passing this.state.options as a prop to the actual Chart object from ApexCharts that when the bar is clicked, the event registers from the Chart object instead of SummaryChart and perhaps that is why I am receiving the error.
app.js:66798 Uncaught TypeError: Cannot read property 'handleBarClick'
of undefined
Issue
In the constructor this.props hasn't been set yet.
Solution
Access the props that were passed to the constructor.
constructor(props) {
super(props);
this.state = {
options: {
chart: {
events: {
dataPointSelection: function (event, chartContext, config) {
props.handleBarClick();
}
}
}
}
};
}

ReactJS render element by ref

I am trying to render an parent-component which has two children. The rendering of the children will switch, so one time there will be only the first child rendered, another time it will be the last and finally it will switch back to the first child (which then should contain all the values shown before).
I thought this would be simple but it turned out that it is not.
Now to the problem: Whenever the method switchContainer is called, it will switch the container and render the other. However all member-variables, props and states are getting lost and it basically reinstanciated the child-component from scratch.
Is there a way to save the child-components "as-is" and once it is getting re-rendered, it will hold all the member-variables, props and states again?
I know that you can send props and states to the element like this:
<Child props={<data>} states={<data>}>
but this doesn't solve the issue with the missing membervariables and in my opinion it isn't a smooth solution.
My attempt so far is (this is just a mockup):
class Parent extends React.Component<any,any> {
private firstContainer:any;
private secondContainer:any;
private currentContainer:any;
constructor(props:any) {
super(props);
this.firstContainer = <Child>;
this.secondContainer = <Child>;
}
public render() {
return (
<div>
{this.currentContainer}
</div>
);
}
public switchContainer() {
if(this.currentContainer === this.firstContainer) {
this.currentContainer = this.secondContainer;
}
else {
this.currentContainer = this.firstContainer;
}
this.forceUpdate();
}
}
class Child extends React.Component<any,any> {
private anyValue:string;
constructor(props) {
this.change = this.change.bind(this);
}
public render() {
return (
<input onChange={this.change} value={this.anyValue}/>
);
}
private change(e:any) {
this.anyValue = e.target.value;
}
}
You can try maintaining a state and update children in render instead of saving child as firstContainer and secondContainer
class Parent extends React.Component<any, any> {
constructor(props) {
super(props);
this.state = {
firstChild: true
};
}
public render() {
const { firstChild } = this.state;
<div>
<Child1 show={firstChild}/>
<Child2 show={!firstChild} />
</div>
}
public switchContainer() {
this.setState(({ firstChild }) => ({ firstChild: !firstChild }));
};
}
And in child component, handle show to showContent otherwise render null. If you want to retain state, you should not unmount the component.

React State not available from Parent?

I have a form with a child component that renders as a table.
ParentComponent extends React {
state = {
anArray: []
}
<ParentComponent>
<table>
map ( thing => <ChildComponent {someFunction= this.updateFunction;} />
When ChildComponent maps the data to individual TD's. In my onChange in the ChildComponent, I'm invoking
onChange = this.props.someFunction();
and the code is hitting my breakpoint which is great. It calls someFunction in the ParentComponent. In someFunction, I'm trying to access the parent's state so I can match the onChanged TD with the proper index in the array but I'm getting undefined.
someFunction(id) {
const index = this.state.anArray.findIndex( x => x.id === id) ;
if (index === -1)
// handle error
console.log("DIDN'T FIND ID: " + id);
});
}
Why wouldn't I have access to state on the function invocation from the ChildComponent? I expected to be able to access it.
It's not clear from the posted code, but I guess you haven't bind the someFunction and you have the context of the child, instead of parent's.
ParentComponent extends React {
constructor(props){
super(props)
this.someFunction = this.someFunction.bind(this)
}
someFunction(){
...
}
render(){
...
}
}
If you have the necessary babel plugins you can even do
ParentComponent extends React {
someFunction = () => {
...
}
render(){
...
}
}

React- createRef() Api - this.child.current is null

In order to allow my parent component (JsonFetcher) to access values from my child component (Display), I tried using createRef() API that just came of this patch 16.3
Following the "Adding a Ref to a class Component" example in this document, here's what I tried in my code:
class JsonFetcher extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
this.state = {
data: [],
}
}
componentDidMount() {
this.updateContent(this.props.mainUrl)
}
updateContent(mainUrl){
fetch(mainUrl)
.then((responseJsonAnyUrl) => responseJsonAnyUrl.json())
.then((responseJsonAnyUrl) => {
this.setState({
mainUrl: mainUrl,
jsonObject: responseJsonAnyUrl
},
function () {
this.timeout = setTimeout(
function(){
//let ind = this.child.current.getCurrentIndex
//tyring to get values from child...
//if index === length-1
this.updateContent(mainUrl)
//else
//retry this function in 5 seconds
//
}.bind(this, mainUrl)
,
20000)
}.bind(this))
})
}
interpretJson() {
/*
*some code
*/
return(
<Display content={contentListArray} ref={this.child}/>
)
}
render() {
if(this.state.jsonObject){
return (
<div>
<div> {this.interpretJson()} </div>
</div>
)
}else
return(
null
)
}
}
So, I created the ref in the constructor, linked it to the child component Display in the end of interpretJson() method and then i'm trying to use the the child method in my timeOut() function. However I get the following error:
"TypeError: Cannot read property 'getCurrentIndex' of null "
What am I doing wrong that's not letting me call the child methods so I can simulate the pseudo-code I have commented?
(Edit) Notes:
My child component Display is not a stateless component, it's a
class.
I already tried calling <Display> in the render instead but the
problem remained.
Use arrow function to bind this method to the class. This way, the this in this.child will bind to the class component
interpretJson = () => {
/*
*some code
*/
return(
<Display content={contentListArray} ref={this.child}/>
)
}
if the above answer doesn't work then do this
constructor(props) {
super(props);
this.interpretJson = this.interpretJson.bind(this);//bind function to class
this.child = React.createRef();
this.state = {
data: [],
}
}
interpretJson() {
/*
*some code
*/
return(
<Display content={contentListArray} ref={this.child}/>
)
}
I also encountered this issue (I'm using typescript)
private modal = React.createRef<HTMLDivElement>()
// ...
public componentDidMount() {
console.log(this.modal)
}
// ...
public render() {
// ...
<div ref={this.modal} className="modal fade"
// ...
Output. From start is null, then is populated after some little time:
The problem was that in render method I exited early, and ref code was not reached
public render() {
const { data } = this.state
// here we return early, ref bellow is not reached
// and in componentDidmount we can't rely on this.modal.current
// this.modal.current will be populated only if data is not null
if (data === null) { return null }
return (
<div ref={this.modal} className="modal fade"
// ...
same problem in example in bellow example
example: https://codesandbox.io/s/ymvxj5pqmx

Resources