React.js通过单个父级在不同子级之间传递道具

时间:2017-07-05 12:47:08

标签: javascript reactjs ecmascript-6

我有一个前端控制台,我试图做出反应,使用侧边菜单来过滤数据库中显示在动态生成的表格中的结果。

组件的层次结构如下:

App.js
|
|--SideMenu.js
|--ResultsTable.js

所以我理解父母可以访问子组件中的道具,也可以将道具传递给子组件。我试图做的是让sidemenu通过父App.js与结果表对话(除非有让孩子们直接沟通的方法吗?)并相应地更新表格,但是我和#39;我遇到了一个奇怪的问题。当我单击过滤器或重置按钮(在SideMenu.js中)时,在结果表组件中拾取道具的延迟需要我在注册之前单击按钮2或3次。我确信这个解决方案很简单,但到目前为止它还没有找到我。我认为当App.js将新道具传递回ResultTable.js时会出现问题,但我并不完全确定如何修复它。

这是我的SideMenu.js代码

export default class SideMenu extends React.Component{

    constructor(){
        super();

        this.state={

            serviceParam: '',
            filterParam: '',
            services: [],
        }

        this.handleServiceChoice = this.handleServiceChoice.bind(this);
        this.handleSearch = this.handleSearch.bind(this);
        this.getServices = this.getServices.bind(this);
        this.handleReset = this.handleReset.bind(this);

    }

    componentWillMount(){

        this.getServices();
    }

    getServices(){
        const _this =this;
        let servicesData;

        let url = "http://mydevsite.ie/cgi-bin/log-queries/api/services";

        fetch(url)
            .then((resp) => resp.json())
            .then(function(data){

                servicesData = data;

                console.log("servicesData");
                console.log(servicesData);

                _this.setState({
                    services: servicesData
                });
            });
    }

    handleReset(){
        this.setState({
            serviceParam: null,
            filterParam: null,
        });

        let dropdownArrow = document.createElement("i");
        dropdownArrow.setAttribute("class", "material-icons right");
        dropdownArrow.innerHTML = "keyboard_arrow_down";
        document.getElementById("serviceDisplay").innerHTML = "Services";
        document.getElementById("serviceDisplay").appendChild(dropdownArrow);

        this.props.filterCallback(this.state.serviceParam);
    }

    handleSearch(){


        if(document.getElementById('search').value && this.state.serviceParam){
            let filterParam = "&search="+document.getElementById('search').value;
            console.log('In child - search 1');
            console.log(filterParam);

            let parentProps;
            parentProps= this.state.serviceParam+filterParam;
            this.props.filterCallback(parentProps);
        } else if (document.getElementById('search').value){
            let filterParam = "?search="+document.getElementById('search').value;
            console.log('In child - search 2');
            console.log(filterParam);

            let parentProps;
            parentProps=filterParam;
            this.props.filterCallback(parentProps);
        } else{
            let filterParam = this.state.serviceParam;
            console.log('In child - search 3');
            console.log(filterParam);

            let parentProps;
            parentProps=filterParam;
            this.props.filterCallback(parentProps);
        }



    }

    handleServiceChoice(e){
        console.log('sidebar target id');
        console.log(e.target.id);

        let serviceParam;
        let dropdownArrow = document.createElement("i");
        dropdownArrow.setAttribute("class", "material-icons right");
        dropdownArrow.innerHTML = "keyboard_arrow_down";
        document.getElementById("serviceDisplay").innerHTML = e.target.id;
        document.getElementById("serviceDisplay").appendChild(dropdownArrow);

        serviceParam = '?service='+e.target.id ;

        this.setState({
            serviceParam: serviceParam,
        });

    }

    render(){
        return(

            <ul className="side-nav fixed blue accent-1">
                <li className="logo"></li>

                <li>
                    <a id="serviceDisplay" href="#" className="dropdown-button waves-effect" data-activates="services">Services<i className="material-icons right">keyboard_arrow_down</i></a>

                        <ul id="services" className="dropdown-content">
                            {this.state.services.map((dropdown)=>{
                                return(
                                    <li key={dropdown.service}>
                                        <a id={dropdown.service} href="#" className="waves-effect" onClick={this.handleServiceChoice}>{dropdown.service}</a>
                                    </li>
                                );
                            })}                 
                        </ul>

                </li>

                <li className="bold"><a href="#">Supplier ID Search</a></li>
                <li className="search">
                    <div className="container center-align">
                        <input id="search" type="text" placeholder="Enter ID here" className="validate blue accent-2"></input>

                        <button className="btn blue accent-2 waves-effect" type="submit" onClick={this.handleSearch}>
                            Filter
                            <i className="material-icons right">search</i>
                        </button>
                    </div>
                </li>
                <li >
                    <div className="container center-align">
                        <button className="btn blue accent-2 waves-effect" type="submit" onClick={this.handleReset}>
                            Reset Logs
                            <i className="material-icons right">autorenew</i>
                        </button>
                    </div>
                </li>


            </ul>
        );



    };
}

和ResultsTable.js:

export default class ResultsTable extends React.Component{

    constructor(){
        super();
        this.state = {
            logs: [],
            xml: '',
            render_xml: false,
        }

        this.ResultsTable = this.ResultsTable.bind(this);
        this.handleRequestXML = this.handleRequestXML.bind(this);
        this.handleResponseXML = this.handleResponseXML.bind(this);
        this.returnToLogs = this.returnToLogs.bind(this);
        this.renderTable = this.renderTable.bind(this);
        this.renderXml = this.renderXml.bind(this);
    }

    componentWillMount(){
        console.log('Child - In componentWillMount!');
        this.ResultsTable();

    }

    componentWillReceiveProps(){
        console.log('Child - In componentWillReceiveProps!');
        console.log(this.props.filter);

        this.ResultsTable();
    }

    returnToLogs(){
        this.setState({
            render_xml:false
        });
    }

    handleResponseXML(e){
        const _this =this;

        _this.setState({
            render_xml: true,
        });

        let id_param = '?_id='+e.target.id+'&type=response';
        let url = "http://mydevsite.ie/cgi-bin/log-queries/api/xml"+id_param;
        fetch(url)
            .then((resp) => resp.json())
            .then(function(data){

                let xml = data;

                console.log("xml");
                console.log(xml);

                _this.setState({
                    xml: xml,
                });

            });
    }

    handleRequestXML(e){
        const _this =this;

        _this.setState({
            render_xml: true,
        });


        let id_param = '?_id='+e.target.id+'&type=request';
        let url = "http://mydevsite.ie/cgi-bin/log-queries/api/xml"+id_param;
        fetch(url)
            .then((resp) => resp.json())
            .then(function(data){

                let xml = data;

                console.log("xml");
                console.log(xml);

                _this.setState({
                    xml: xml,
                });
            });
    }

    ResultsTable(){
        console.log('Child - In ResultsTable!');
        console.log(this.props.filter);

        const _this =this;
        let logData;

        let url = "http://mydevsite.ie/cgi-bin/log-queries/api/logs";



        if(this.props.filter){
            console.log('Child - Service Choice!');
            console.log(this.props.filter);
            url +=this.props.filter;
        }

        fetch(url)
            .then((resp) => resp.json())
            .then(function(data){

                logData = data;

                console.log("logData");
                console.log(logData);

                _this.setState({
                    logs: logData
                });
            });

    }



    renderTable(){
        console.log('In renderTable!');
        return (

            <table className="highlight">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Created</th>
                        <th>Last Changed</th>
                        <th>Service</th>
                        <th>Supplier Identifier</th>
                        <th>Request XML</th>
                        <th>Response XML</th>
                    </tr>

                </thead>
                <tbody>
                {this.state.logs.map((log)=>{
                    return(
                        <tr key={log._id}>
                            <td>{log._id}</td>
                            <td>{log.created}</td>
                            <td>{log.last_changed}</td>
                            <td>{log.service}</td>
                            <td>{log.supplier_identifier}</td>
                            <td><a id={log._id} onClick={this.handleRequestXML} href='#'>Click for XML</a></td>
                            <td><a id={log._id} onClick={this.handleResponseXML} href='#'>Click for XML</a></td>
                        </tr>
                    );
                })}

                </tbody>


            </table>


        );
    }

    renderXml(){
        console.log("In renderXml");
        return(
            <div className="card-panel">
                {this.state.xml}
                <hr/>
                <a className="waves-effect btn blue accent-2" onClick={this.returnToLogs}>Back to logs</a>
            </div>

        );
    }

    render(){
        if(this.state.render_xml){
            return this.renderXml();
        } else {
            return this.renderTable();
        }
    }
}

这是父App.js组件

export default class App extends React.Component{

    constructor(){
        super();
        this.state = {
            filter: null,
        }

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

    handleFilterParam(filter){
        console.log('In parent - handleSearchParam');
        console.log(filter);
        this.setState({
            filter: filter
        });
    }

    render(){
        console.log('In parent - render');
        console.log(this.state.filter);

        return (
            <div className="row">

                <div className="col s4 l3">
                    <SideMenu 
                        filterCallback={this.handleFilterParam}
                    />
                </div>
                <div className="col s12 l9">
                    <Header />
                    <ResultsTable filter={this.state.filter}/>
                </div>

            </div>

        );
    }
}

我仍然对React和ES6很陌生,所以如果其中一些看起来非常业余,请提前道歉。

1 个答案:

答案 0 :(得分:0)

如果有人想知道并查看这个问题,我找到了一个非常简单的解决方案。我以前使用过这种生命周期方法,但直到现在还不太了解它。

因此,在我的ResultsTable组件中,我将此代码添加到'listen'以获取新的道具并相应地更新:

componentWillReceiveProps(nextProps) {
        if(this.props != nextProps) {
            this.props = nextProps;
            this.handleResultsTable();
        }
    }