1

I have a react app which has the following component structure:

App.Js
 Dashboard.js

  Component1.js
    Child1.js
     Subchild1.js
       SubSubChild1.js
       SubSubChild2.js

  Component2.js
    Child1.js
     SubChild1.js

The Dashboard component calls both Component1 and Component2, Component1.js then calls Child1.js, which calls SubChild1.js etc.

The Child1.js component of Component 2:

App.Js
 Dashboard.js

  Component1.js
    Child1.js
     Subchild1.js
       SubSubChild1.js
       SubSubChild2.js

  Component2.js
--> Child1.js
     SubChild1.js

Renders a table, using the following code:

  ... return (

          <div className="table-responsive">
            <table
              id="example"
              data-page-length='4' //https://www.datatables.net/manual/options
              className="table table-bordered table-hover display nowrap margin-top-10 w-p100"
            >
              <thead>
                <tr>
                  <th>Heading 1</th>
                  <th>Heading 2</th>
                </tr>
              </thead>
              <tbody>


                    {props.myStateVariable.map(userWallet => (
                      <SubChild1
                        key={userWallet.id}
                        id={userWallet.id}
                        coin={userWallet.coin}
                        balance={userWallet.balance}
                        loadedWallets={props.loadedWallets}
                      />
                   ...

The table renders just fine initially. Here is the code that renders the rows of the table, in SubChild1.js:

import React from "react";

const SubChild1 = props => {


  return (
    <tr>
      <td>{props.coin}</td>
      <td>{props.balance.toFixed(8)}</td>
    </tr>

  );
};

export default SubChild1;

myStateVariable, is defined in app.js as follows:

const [myStateVariable, setMyStateVariable] = useState(myInitialData);

Now when I update myStateVariable from SubSubChild2.js:

App.Js
 Dashboard.js

  Component1.js
    Child1.js
     Subchild1.js
       SubSubChild1.js
   --> SubSubChild2.js

  Component2.js
    Child1.js
     Subchild1.js

By calling a function passed as a prop from SubChild1 to SubSubChild2, which executes the following:

 props.setMyStateVariable(myNewData);

The data in the table rendered by SubChild1.js under Component2.Js:

App.Js
 Dashboard.js

  Component1.js
    Child1.js
     Subchild1.js
       SubSubChild1.js
       SubSubChild2.js

  Component2.js
    Child1.js
  --> SubChild1.js

is not updated. It is only updated if I navigate to a different Route path, and then back to the original Route which renders Dashboard.js.

When I do that the table is updated fine. The problem Is I need to have the table updated, as soon as the myStateVariable has been updated from SubSubChild2.js , and not only after I navigate away from and back to the Route which calls Dashboard.js component.

Edit: This is how the state variable and update function are being passed down from props.

The actual update of the state variable is triggered when SubSubChild2.js calls a function which was passed to it as a prop from SubChild1.js:

From the start...

In App.Js the state var is defined using:

const [myStateVariable, setMyStateVariable] = useState(myInitialData);

App.JS then calls Dashboard.js:

 <Dashboard          
     myStateVariable={myStateVariable}
     setMyStateVariable={setMyStateVariable}
 />

Dashboard.js calls Component1.js and Component2.js, as follows:

   <Component1 {...props}/>
   <Component2 {...props}/>

Component1.js calls Child1.js, as follows:

<Child1 {...props}/>

Child1 calls SubChild1.js as follows:

<SubChild1
    myStateVariable={props.myStateVariable}
    setMyStateVariable={props.setMyStateVariable}
 />

SubChild1 calls SubSubChild2 with the below code:

return (
        <div>
        {showButton === true ? <SubSubChild1/> : null}
        {showResult === true ? <SubSubChild2 updateTableData={updateTableData}/> : null}
        </div>
    )

updateTableData() is a function in SubChild1 which is passed as a prop to SubSubChild2.

const updateTableData = () => {
 updateSteps(myNewData);
}

updateSteps() is also in SubChild1, and actually executes the set state function:

const updateSteps = (myNewData) => {
   props.setMyStateVariable(myNewData);
}

In SubSubChild2, this actual change of state is triggered using props.updateTableData()

Gary
  • 1,086
  • 2
  • 13
  • 39
  • 2
    are you doing any memo or shouldComponentUpdate? can you show us how you are passing the update function and the state var down from props? – azium Apr 11 '20 at 23:29
  • @azium Thank you for your comment, I should have included that. I have added an edit to the bottom of the question. I'm not using any memo or shouldComponentUpdate. – Gary Apr 12 '20 at 00:08

2 Answers2

1

Perhaps the new data is still manipulating the same initialized object?

For example, if you are adding/removing values from an array, you need to create a new object to trigger the state change. e.g.

const data = [...myNewData];
props.setMyStateVariable(data);

instead of this

myNewData.push(dataObj)
props.setMyStateVariable(myNewData);

Cf. this SO question;

nrako
  • 2,952
  • 17
  • 30
0

I would say you pass a handler function from <Dashboard/> down to <SubSubChild2/> and call it to update the state in the <Dashboard/> component since it's the closest parent to both <SubSubChild2/> and <SubChild1/> of <Component2/>. The updated state has then to be passed down as props to Component2 and then SubChild1.

the render() method in <Dashboard/>:

return (
   <Component1 handleChange={this.handleChange}/>

   <Component2 stateName={this.state.stateValue} />
)
G. DIb
  • 1
  • 1