A
A
Amir2017-03-15 17:12:19
React
Amir, 2017-03-15 17:12:19

How to update child component from parent?

Good afternoon.
The essence of the question is this:
There are two components - parent:

export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            someVar: 0
        }
    }

    setVar(some) {
        this.setState({someVar: some});
    }

   render() {
        return (<Child someVar={this.state.someVar} setVar={this.setVar.bind(this)} />);
   }
}

and child:
export default class Child extends Component {
    constructor(props) {
        super(props);
        this.state = {
            someVar: 0,
        }
    }

    getNext() {
        this.setState({someVar: this.state.someVar + 1});
    }

    componentWillReceiveProps(nextProps) {
        this.setState({someVar: nextProps.someVar});
    }

    componentDidMount() {
        this.getNext();
    }

   render() {
       // это просто пример. всё немного сложнее. но не очень.
       let btn = (<button type="button" onClick={this.props.setVar.bind(this, this.state.someVar)}>Go</button>
       return (<div>{this.state.someVar}</div>);
   }
}

So when you click on the "Go" button, the child component is not redrawn. What am I doing wrong?
Thanks in advance for your replies.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Amir, 2017-03-15
@Guedda

Yes, I tried this option first, but it did not help. Remade a bit, but now there is another error related to this question. Apparently it's better to describe the code I have - I'll try:
Parent component:

export default class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            response: false,                           
            selfUser: undefined,                       
            someId: undefined,
        }
    }

    getUser() {
        var self = this;
        someAjax().then(function(user) {
            if (user) {
                self.setState({response: true, selfUser: user, someId: user.someId});
            } else {
                self.setState({response: true, selfUser: undefined, someId: undefined});
            }
        });
    }

    setId(id) {
        this.setState({someId: id});
    }

    componentDidMount() {
        this.getUser();
    }


    render() {
        if (this.state.response) {
            let page;
            if (this.state.selfUser) {
                        page = (
                            <Child
                                sometId={this.state.someId}
                                setId={this.setId.bind(this)} />
                        );
            } else {
                page = (<div>No user</div>)
            }
            
            return (
                <div>
                    {page}        
                </div>
            )
        } else {
            return (
                <div>No response</div>
            )
        }
    }

}

Child component:
export default class Child extends Component {

    constructor(props) {
        super(props);

        this.state = {
            status: "none",
            someData: undefined,
        }
    }

    getData() {
        $.ajax({
            url: 'someUrl'
            type: 'GET',
            success: function(data) {
                 this.setState({ status: "success", someData: data});
            }
        });
    }

    goToNextPage(item) {
        this.props.setId(item.Id);
    }

    renderDataChild(item) {
        let goToDataChildPage = this.goToNextPage.bind(this, item);
        return (
            <div key={item.Id} className="brick main-shadow">
                <div className="brick-inner" onClick={goToDataChildPage }><strong>{item.Name}</strong></div>
            </div>
        );
    }

    componentDidMount() {
        this.getData();
    }

    render() {
        switch (this.state.status) {
            case "none":
                return (<p></p>);
            case "success":
                if (this.state.someData) {
                    let someData = this.state.someData.values;
                    let tens = someData.map(function(obj) {
                        return this.renderDataChild(obj);
                    }.bind(this));

                    return (
                        <div>
                            {tens}
                        </div>
                    );
                } else {
                    return (
                        <div>No data</div>
                    );
                }
        }
    }

So now I get everything for the first time, and when I change someId (I click on some brick), JS writes an error
swearing at the line
What am I doing wrong? It's all related to the props of the parent component.

O
Oleg Drapeza, 2017-03-15
@SuperOleg39ru

First, you've declared a btn variable, but you're not returning it to render.
Secondly, why declare the someVar property in Child this.state if it is available to you from this.props?
There is no need to bind this Child to the App callback, because then the props.setVar method will call setState on the Child - this.props.setVar.bind(this, this.state.someVar)}
In short, React itself updates the component if its props change (which happens through the parent's callback).

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

        this.state = {
            someVar: 0
        }

        this.setVar = this.setVar.bind(this);
    }

    setVar(some) {
        this.setState({someVar: some});
    }

   render() {
        return (<Child someVar={this.state.someVar} setVar={this.setVar} />);
   }
}

export default class Child extends Component {
    constructor(props) {
        super(props);

        this.handleClick = this.handleClick.bind(this);
        this.getNext = this.getNext.bind(this);
    }

    getNext() {
        return this.props.someVar + 1;
    }

    handleClick() {
        this.props.setVar( this.getNext() )
    }

   render() {
       let btn = (<button type="button" onClick={this.handleClick}>Go</button>
       return (<div><btn /> {this.props.someVar}</div>);
   }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question