Nina
Nina

Reputation: 509

How to await setting to state before mapping array?

'm trying to map some data that I have stored in an array (the screenshot below), but I can't seem to access it, because it is loaded asynchronously. How could I await the data? Is there a way to do it in the render function?

 render() {
         
        return (
          {this.state.serials.map((number) => {
    return number.s && number.s.length? 
    (
        <h2 > {number.s[0].a}</h2>
  ) : null
})}
        )
    }

This is componentDidMount() where I get my data:

componentDidMount() 
        const uid = this.state.user.uid;
        const gatewayRef = db.ref(uid + '/gateways');
        gatewayRef.on('value', (gateways_nums) => {
            const serialsArr = [];
          gateways_nums.forEach((gateway_num) => {
            const serialRef = db.ref('gateways/' + gateway_num.val()['gateway'])
            const last_temps =[];
            serialRef.on('value', (serials)=>{ 
                const ser = []
                serials.forEach((serial)=>{
                    ser.push(serial.val()['serial'])
                })
                last_temps.push({a: gateway_num.val()['gateway'], b: ser})
            })
            serialsArr.push({s:last_temps})
          });
          this.setState({serials:serialsArr})
        });
      }

I would really appreciate any help!

Upvotes: 2

Views: 56

Answers (2)

Nina
Nina

Reputation: 509

I managed to get it working by changing the algorithm a bit. With this code there is no need for awating data:

    componentDidMount() {
    const uid = this.state.user.uid;
    const serialRef = db.ref(uid + '/gateways');

    serialRef.on('value', (serial_numbers) => {
      const serials = [];
      serial_numbers.forEach((serial_number) => {
        const za = serial_number.val()['gateway'];
        const last_temps = [];
        const tempRef = db.ref('gateways/' + za);
        tempRef.orderByChild("serial").on('value', (temps) => {
          const temparray = [];
          temps.forEach((temp) => {
            temparray.push(temp.val());
          })
          const last_temp = temparray;
          last_temps.push({ l: last_temp, za });
          this.setState({ last_temps: last_temps })
        })
        serials.push({ s: last_temps });
      });
      this.setState({ serials: serials });
    });
  }

Upvotes: 0

jabuj
jabuj

Reputation: 3639

Try this:

render() {
  if(!this.state.serials) {
    // Ideally you should draw some loading spinner here
    // to indicate that data is not ready yet. But for a quick
    // solution you can just draw nothing
    return null
  }

  // Also "return ({ this.state.serials.map() })" is not valid syntax
  // you either need to return just an array without using braces, or
  // use some JSX tag and put braces inside of it
  return (
    <div>
        {this.state.serials.map(serial => ...)}
    </div>
  )
}

Speaking of invalid syntax with braces, you could also do

return this.state.serials.map(serial => ...)

Or (better)

return (
  <>
    {this.state.serials.map(serial => ...)}
  </>
)

If you don't want an extra div around your data

Upvotes: 2

Related Questions