Search code examples
javascriptreactjsreact-reduxreact-props

ReactJS what is the proper way to wait for prop to load to avoid crashing my page?


all,

I am building a local website for myself for stocks. Currently I have a store that communicates with my tomcat instance to get stock market data, this works flawlessly.

on my frontend I am attempting to display my data but sometimes it works, sometimes it does not work and I get an "this child prop does not exist" so this is what I implemented:

try{
          cellRend = this.cellRenderer;
          columnLen = this.props.selectedStock.Revenue.length;
          this.state.isLoading = false
        }catch(error){ 
           cellRend = this.cellRendererEmpty;  
           columnLen = 10;
        }
        if (this.state.isLoading === true){
            return <div>Loading!</div>
        }

where cellRenderer is my table, cellRendererEmpty is an empty table.

this kind of works and some times it will just display Loading! forever. so my question is what is the correct way to wait for a prop?

here is my full code:


const dispatchToProps = dispatch => {
    return{
      getSelStock: (stockId) => dispatch(stockActions.getSelStock(stockId))  
    };
}


class stockPage extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            columnLen:10,
            data:null,
            isLoading:true
        }
        console.log(this.props.isLoading)
        this.cellRenderer = this.cellRenderer.bind(this);
        this.render = this.render.bind(this);
    }
    
    cellRenderer({ columnIndex, key, rowIndex, style }) {   
            return (
      <div className={"app"} key={key} style={style}>
          <span></span>
        {rowIndex === 0 ? (`${this.props.selectedStock.Revenue[columnIndex].date}`) : (
          <span>{`${this.props.selectedStock.Revenue[columnIndex].value}`}</span>
        )}
      </div>
    );
        
    }
    
    cellRendererEmpty({ columnIndex, key, rowIndex, style }) {
            return (
      <div className={"app"} key={key} style={style}>
        {rowIndex === 0 ? (`${columnIndex}`) : (
          <span>{`${columnIndex}`}</span>
        )}
      </div>
    );
        
    }
    
    
    
    
    render() { 
        var cellRend, columnLen
                console.log("Hey")
       this.props.getSelStock(this.props.match.params.stockId);        
        try{
          cellRend = this.cellRenderer;
          columnLen = this.props.selectedStock.Revenue.length;
          this.state.isLoading = false
        }catch(error){ 
           cellRend = this.cellRendererEmpty;  
           columnLen = 10;
        }
        if (this.state.isLoading === true){
            return <div>Loading!</div>
        }
        return(
                
                <div>
                <h1>{this.props.match.params.stockId}</h1>
                    <AutoSizer disableHeight>
      {({ width }) => (
        <MultiGrid
          cellRenderer={cellRend}
          columnWidth={125}
          columnCount={this.state.columnLen}
          enableFixedColumnScroll ={1}
          enableFixedRowScroll ={1}
          fixedColumnCount
          fixedRowCount
          height={300}
          rowHeight={70}
          rowCount={2}
          style={STYLE}
          styleBottomLeftGrid={STYLE_BOTTOM_LEFT_GRID}
          styleTopLeftGrid={STYLE_TOP_LEFT_GRID}
          styleTopRightGrid={STYLE_TOP_RIGHT_GRID}
          width={width}
          hideTopRightGridScrollbar
          hideBottomLeftGridScrollbar
          hideBottomRightGridScrollbar
        />
      )}
    </AutoSizer>
        </div>
                )
    
    
    }
    
}
export default connect(mapStateToProps, dispatchToProps)(stockPage);

Solution

  • From your title, I assume that when your page loads, you are fetching data then you use that data in the page. However, during initial load and when your fetching is still in process, your data is still null and your app will crash because the code is expecting data to have a value which it needs to use...

    What you can do is while the data is fetching, then do not display the rest of the page yet (ie. you can just display a giant spinner gif), then once the fetching is complete then update isLoading state... Or you can set an initial value for the data so the page won't crash on load...

    EDIT: so using react lifecycle fixed your problem as per your comment... anyways just wanna add that you may want to use async/await instead of setTimeout like you did in your comment.. This is what the code might look like for async/await in lifecycles...

    componentDidMount() {
        const fetchData = async () {
            await this.props.getSelStock() // your dispatch
    
            // the state you want to update once the dispatch is done
            this.setState({isLoading: false}) 
        }
    
        fetchData();
    }