0

I am trying to render a table in which each row (1,2,3) has expandable rows (a,b,c). Row will get data from API/rows, expandable rows will get data from API/rowId?expandableRows. expandable rows will follow it's row when rendered like this:

row  col1 col2 col3
1     x    x    x
a     x    x    x
b     x    x    x

2     x    x    x
a     x    x    x  
  
3     x    x    x
a     x    x    x   

Here is my code:

class Table extends Component {
  constructor(){
    super();
    this.state={ rowList: [] }
  }
  componentDidMount() {
    fetch(API/rows)
     .then(results=>{return results.json()})
     .then(rows =>{
         let rowList= rows.map(row=> {
             return (
               <react.Fragment>
                <tr><td>{row.info}</td></tr>
                {this.getExpandableRow(row.id).then(exrows=>{return exrows})}
               </react.Fragment>
              )
         })
        this.setState(rowList: rowList);
      })
  }
   
  getExpandableRow(id) {
     return fetch(api/rowid?expandableRows)
               .then(results=>{return results.json();})
               .then(expandData=>{
                     data.map(dat=>{
                       return (
                              <tr><td>expandrow.info</td></tr>
                              )
                     })
                    console.log(expandData)
                })
  }

  render(){
      return (<Table>{this.state.rowList}</Table>)
  }

}

Now the problem is I can see expand data in console.log, but when calling getExpandableRows function in rows loop, no matter use {this.getExpandableRow(row.id)} or {this.getExpandableRow(row.id).then(exrows=>{return exrows})}, I got the error:

Objects are not valid as react child(found:[object promise]), if you meant to render a collection of children, use an array instead.

What should I do to get expandable row data when looping rows?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
MARS
  • 33
  • 6
  • Make the functions `async` and `return await fetch(//...` instead. – matthew-e-brown Dec 20 '19 at 16:50
  • `.then(results=>{return results.json();})` has an unnecessary `return` and `.then(expandData=>{...})` is missing a `return` – Andreas Dec 20 '19 at 16:50
  • You can't use promises in the middle of a React rendered component like that, `{this.getExpandableRow(row.id).then(exrows=>{return exrows})}` – TKoL Dec 20 '19 at 16:51
  • 1
    Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – ASDFGerte Dec 20 '19 at 16:51

1 Answers1

0

I haven't tested this, but I THINK you might be able to get away with this:

componentDidMount() {
    fetch(API/rows)
     .then(results=>{return results.json()})
     .then(async rows =>{
         // this will be an array of promises
         let rowExpPromiseList = rows.map(row=> {
             return this.getExpandableRow(row.id);
         });
         // I believe this will be an array of components at this point
         const rowExpList = await Promise.all(rowExpPromiseList);
         const rowList = rows.map((row, index) => (
               <react.Fragment>
                <tr><td>{row.info}</td></tr>
                {rowExpList[index]}
               </react.Fragment>
              ));
         this.setState(rowList: rowList);
      })
  }

You get the expandable rows before you try to render the react components that require them.

TKoL
  • 13,158
  • 3
  • 39
  • 73
  • hi TKoL, thank you very much for your response, after i tried your code, it doesn't give me any error, but expandable rows didn't show up either, I added a console.log after , it just returned comma, not quite sure what's going wrong. – MARS Dec 20 '19 at 17:19
  • It just returned a comma? That doesn't make sense, `await Promise.all()` should give an array. Can you not set breakpoints in your application to see what the values are? – TKoL Dec 20 '19 at 17:22
  • my webstorm debug has some problem, which cannot run properly, but I tried this: let rowExpPromiseList = rows.map(row=> { return this.getExpandableRow(row.id); }); console.log(rowExpPromiseList); const rowExpList = await Promise.all(rowExpPromiseList); console.log(rowExpList); the first console returned three items: [object promise] [object promise] [object promise] which make sense as my api have three rows, each row have an array of expandable rows returned , but the second console.log just returned: , , – MARS Dec 20 '19 at 18:38
  • 1
    hi TKoL, thank you very much for your help, I make it work, just changed getExpandableRows to : async getExpandableRow(id) { const data = await fetch(api/rowid?expandableRows) .then(results=>{return results.json();}) .then(expandData=>{ return data}) const expData = data.map(dat=>{ return ( expandrow.info ) }) console.log(expandData) } – MARS Dec 20 '19 at 18:56