5

How can I make it so that my components render after getting the data from an axios GET request?
I have the following components:

class CardPool extends React.Component{
    constructor(props){
        super(props);

        this.state = {
            cardListBacklog: [],
        };
    }

    componentWillMount(){
        axios.get('/cards').then(function(response){
            this.setState({cardListBacklog: response.data});
        }.bind(this));
    }

    render(){

        return(
            <div class="row">
                <Section name="Construction of Component 1 with a huge ass name that wont really fit in the section">
                    <Column columnName="BACKLOG">
                        <CardList id="card-list-1" column="0" cardList={this.state.cardListBacklog}/>
                    </Column>
                </Section>
            </div>
        );
    }
}

and

class CardList extends React.Component{
    constructor(props){
        super(props);

        this.state = {
            cardList: [],
            laneID: this.props.column
        }
    }

    componentWillMount(){
        this.setState({
            cardList: this.props.cardList,
        });
    }
render(){
        const {connectDropTarget} = this.props;

        return connectDropTarget(
            <div class={"card-list " + this.addClass()} id={this.props.id}>
                {   
                    this.state.cardList ?
                        this.state.cardList.map((card) => {
                            return <Card key={card.id} state={card} laneID={this.state.laneID}/>
                        })
                        : null
                }
            </div>
        );
}

The problem is that the state's cardListBacklog passed to the CardList is not being updated, and the cardList in CardList component remains empty. What am I doing wrong? Could it be because I am setting state properties using the props?

3 Answers 3

4

You are not giving a chance to CardPool component to re-render when response arrives via axios call.

Modify the render function of CardPool component like the following:

return this.state.cardListBacklog.length
        ? <div class="row">
            <Section name="Construction of Component 1 with a huge ass name that wont really fit in the section">
                <Column columnName="BACKLOG">
                    <CardList id="card-list-1" column="0" cardList={this.state.cardListBacklog}/>
                </Column>
            </Section>
          </div>
        : null;

This demo demonstrates the barebone implementation

Sign up to request clarification or add additional context in comments.

2 Comments

This answer is ok, there is one more issue. CardList has a list in its state based on props that I modify using react-plugin'(update` feature for state). How do I make it so that when the state in the CardPool changes, the state in the CardList changes? So far, the last state changes only when it mounts. Can I modify props? I only perceive them as read only objects.
You can do the state change of CardList in its componentWillReceiveProps lifecycle method.
1

componentWillMount lifecycle function is execute only once and hence, when the cardList is available in the parent after the axios request, the child component's componentWillMount had already executed and hence its state is not updated. Also its not a good idea to set the state which is directly derivable from props, you should instead pass a handler from the parent that is called from Child

class CardPool extends React.Component{
    constructor(props){
        super(props);

        this.state = {
            cardListBacklog: [],
        };
    }

    componentWillMount(){
        axios.get('/cards').then(function(response){
            this.setState({cardListBacklog: response.data});
        }.bind(this));
    }

    removeCard = (card) => {
        //do what you need to update cardListBacklog
     }

    render(){

        return(
            <div class="row">
                <Section name="Construction of Component 1 with a huge ass name that wont really fit in the section">
                    <Column columnName="BACKLOG">
                        <CardList id="card-list-1" column="0" cardList={this.state.cardListBacklog} removeCard={this.removeCard}/>
                    </Column>
                </Section>
            </div>
        );
    }
}

and

class CardList extends React.Component{
    constructor(props){
        super(props);

        this.state = {
            cardList: [],
            laneID: this.props.column
        }
    }

    render(){
        const {connectDropTarget} = this.props;

        return connectDropTarget(
            <div class={"card-list " + this.addClass()} id={this.props.id}>
                {   
                        this.props.cardList.map((card) => {
                            return <Card key={card.id} state={card} removeCard={() => this.props.removeCard(card)} laneID={this.state.laneID}/>
                        })
                        : null
                }
            </div>
        );
}

Comments

0

I was able to pass data from parent to children after an axios request in this way:

Parent Component

export default class App extends React.Component {
constructor(props) {
    super(props);

    this.state = {
        peoples: []
    };
}

componentDidMount() {
    axios.get(`https://swapi.co/api/people`).then(res => {
        const peoples = res.data.results;
        this.setState({ peoples });
    });
}
render() {
    const { peoples } = this.state;
    return (
        <div>
            <Header />
            <Main peoples={peoples} />
            <Footer />
        </div>
    );
}

Child Component

export default class Main extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        peoples: []
    };
}
componentDidUpdate(prevProps) {
    const { peoples } = this.props;

    if (peoples !== prevProps.peoples) {
        this.setState({ peoples });
    }
}

render() {
    const { peoples } = this.state;
    return (
        <div>
            {peoples
                ? peoples.map(people => {
                      return <div>people.name</div>;
                  })
                : null}
        </div>
    );
}

The problem is that axios request is asynchronous and is possible to data be only received after the child component be mounted. So we need to check if response is received with react hook componentDidUpdate and compare the first value with the new value received to let render print properly.

https://reactjs.org/docs/react-component.html#componentdidupdate

1 Comment

Welcome to SO! When you post an answer, try to explain your P.O.V., as there are more answers, not just paste the code, even if right.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.