仅当单击父组件的按钮“提交”两次时,子组件才会重新渲染。

时间:2019-01-26 02:19:25

标签: reactjs jsx

我遇到两个问题。父组件CustomerTableTools将表(页面)的大小发送到子组件(FetchCustomerTable)。当我单击“提交”时,“父”状态将发生变化,但是除非再次单击“提交”,否则子级将不会重新渲染。输入和“提交”按钮位于父级内部,表位于子级内部。我在这里错过了重要的细节吗?我认为如果父母将其状态作为道具发送给孩子并且状态发生变化,则应该重新渲染孩子。

该表的数据由this.props.customers填充 谢谢大家的宝贵时间。我只想学习,感谢您的投入。

//***************************
//CustomerTableTools (Parent):
//****************************

import React, { Component } from 'react';
import FetchCustomerTable from './FetchCustomerTable'
import LoadingSpinner from '../Util/LoadingSpinner'
import ErrorStatus from '../Util/ErrorStatus'
import axios from "axios/index";

class CustomerTableTools extends Component {

constructor(props) {
    super(props);
    this.state = {
        limitChanged: false,
        page: 0,
        limit: 10,
        value: 10,
        customers: [],
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    console.log("props: "+JSON.stringify(props))
}


handleChange(event) {
    if(event.target.value >= 0 && (!isNaN(event.target.value) &&     
(function(x) { return (x | 0) === x; })(parseFloat(event.target.value)))) {
        this.setState({value: event.target.value});
     }
}



componentDidMount() {
    this.setState({limit: this.state.value, limitChanged: true});

    console.log("Fetching data1");
    this.setState({loading: true, statusMessage: <LoadingSpinner/>});

    axios.get("http://localhost:8090/customer/viewCustomers/", {
        params: {
            page: this.state.page,
            limit: this.state.limit
        }
    })
        .then(response => {
            // console.log("response: "+JSON.stringify(response.data));
            this.setState({
                customers: response.data.content,
                statusMessage: null,
                loading: false
            });
            console.log(this.state.customers);
        })
        .catch(error => {
                console.log(error);
                this.setState({
                    statusMessage: <ErrorStatus error={error.toString()}/>,
                })
            }

        );

}

handleSubmit(event) {
    event.preventDefault();

    this.setState({limit: this.state.value, limitChanged: true});

    console.log("=====HANDLE SUBMIT=====");
    this.setState({loading: true, statusMessage: <LoadingSpinner/>});

    axios.get("http://localhost:8090/customer/viewCustomers/", {
        params: {
            page: this.state.page,
            limit: this.state.limit
        }
    })
        .then(response => {
            // console.log("response: "+JSON.stringify(response.data));
            this.setState({
                customers: response.data.content,
                statusMessage: null,
                loading: false
            });
            console.log(this.state.customers);
        })
        .catch(error => {
                console.log(error);
                this.setState({
                    statusMessage: <ErrorStatus error={error.toString()}/>,
                })
            }

        );
}



render() {

    let tableBody = null;
    tableBody = <FetchCustomerTable customers={this.state.customers}/>

    return(
        <div>
            <div id="grid">
                <div id="item2">

                    <form style={{ position: 'absolute', bottom: 0}} 
                        onSubmit={this.handleSubmit}>
                        <label>
                            <div>Page Size:</div>
                            <input style={{width: '7vh'}} type="number" 
                               value={this.state.value} onChange= 
                               {this.handleChange} />
                        </label>
                        <input type="submit" value="Submit" />
                    </form>
                </div>
            </div>

            {tableBody}
        </div>
    );
}
}
    export default CustomerTableTools

//***************************
//FetchCustomerTable (Child):
//***************************

import React, { Component } from 'react';
import axios from 'axios';
import '../../App.css'
import LoadingSpinner from '../Util/LoadingSpinner'
import ErrorStatus from '../Util/ErrorStatus'
import {BootstrapTable, TableHeaderColumn, ClearSearchButton} from 'react- 
bootstrap-table';
import {Button, Glyphicon} from 'react-bootstrap'


class FetchCustomerTable extends Component {

onAfterSaveCell(row) {
    const customerId = row['customerId'];
    axios({
        method: 'PUT',
        url: `http://localhost:8090/customer/updateCustomer/${customerId}`,
        data: JSON.stringify(row),
        headers:{'Content-Type': 'application/json; charset=utf-8'}
    })
        .then((response) => {
                console.log(response);
                console.log(response.data);
        })
        .catch((error) => {
            console.log(error);
            //logger.error(error);
        });
}

handleDeletedRow(rowKeys) {
    console.log("KEYS DROPPED: "+ rowKeys);
    axios({
        method: 'DELETE',
        url: `http://localhost:8090/customer/deleteCustomers/${rowKeys}`,
        data: rowKeys,
        headers:{'Content-Type': 'application/json; charset=utf-8'}
    })
        .then((response) => {
            console.log(response);
            console.log(response.data);
        })
        .catch((error) => {
            console.log(error);
            //logger.error(error);
        });

}

//Style delete button on top of table
customDeleteButton = (onBtnClick) => {
    return (
        <Button onClick={ onBtnClick }><Glyphicon glyph="remove" /> Delete 
Selected</Button>
    );
}

onSearchChange = (searchText) => {
    console.log("inside search change!");
    this.setState({searchText: searchText});

}

handleClearButtonClick = (onClick) => {
    if(!!this.state.searchText) {
        console.log("Fetching data2");
        //this.setState({loading: true, statusMessage: <LoadingSpinner/>});

        axios.get("http://localhost:8090/customer/searchResults/", {
            params: {
                firstName: this.state.searchText,
                email: this.state.searchText,
                page: this.props.page,
                limit: this.props.limit,

            }
        })
            .then(response => {
                console.log("respsonse: 
"+JSON.stringify(response.data.pageable));
                this.setState({
                    //loading: false,
                    customers: response.data.content,
                    statusMessage: null
                })

                console.log(this.state.customers);
            })
            .catch(error => {
                    console.log(error);
                    this.setState({
                        statusMessage: <ErrorStatus error= 
                                       {error.toString()}/>,
                    })
                }
            );
        onClick();
    } else {
        //TODO: add method to clear search results
    }
}

createCustomClearButton = (onClick) => {
    return (
        <ClearSearchButton
            btnText='Submit'
            btnContextual='btn-warning'
            className='my-custom-class'
            onClick={ e => this.handleClearButtonClick(onClick) }/>
    );
}

render() {
    let content = null;

    //settings for BootStrapTable
    const options = {
        defaultSortName: 'customerId',  // default sort column name
        defaultSortOrder: 'asc',  // default sort order
        afterDeleteRow: this.handleDeletedRow,
        deleteBtn: this.customDeleteButton,
        onSearchChange: this.onSearchChange,
        clearSearch: true,
        clearSearchBtn: this.createCustomClearButton,
        pagination: true,
        nextPage: 'Next',
    };

    const selectRow = {
        mode: 'checkbox'
    };

    const cellEditProp = {
        mode: 'dbclick',
        blurToSave: true,
        afterSaveCell: this.onAfterSaveCell  // a hook for after saving 
                                                cell
    };

    const fetchInfo = {
        dataTotalSize: 100, // or checkbox
    };

    content =
    <div className="tableContainer">
      <BootstrapTable remote={ true } search={ true } striped 
      bordered condensed hover headerStyle={{ fontFamily: 'proxima-                      
                                             nova' }}
      bodyStyle={{ fontFamily: 'proxima-nova' }} 
      data={ this.props.customers } options={ options }
      cellEdit={ cellEditProp } selectRow={selectRow} deleteRow>
        <TableHeaderColumn name='customerId' dataField='customerId' 
          isKey dataSort>Customer ID</TableHeaderColumn>
        <TableHeaderColumn name='lastName' dataField='lastName' 
          dataSort>Last Name</TableHeaderColumn>
        <TableHeaderColumn name='firstName' dataField='firstName' 
          dataSort>First Name</TableHeaderColumn>
        <TableHeaderColumn name='email' dataField='email' 
          dataSort>Email</TableHeaderColumn>
        <TableHeaderColumn name='address' dataField='address' 
          dataSort>Address</TableHeaderColumn>
        <TableHeaderColumn name='city' dataField='city' 
          dataSort>City</TableHeaderColumn>
        <TableHeaderColumn name='state' dataField='state' 
          dataSort>State</TableHeaderColumn>
        <TableHeaderColumn name='zip' dataField='zip' 
          dataSort>Zip</TableHeaderColumn>
        <TableHeaderColumn name='lastEmailSent' 
          dataField='lastEmailSent' dataSort editable={ false }>Last Email 
          Sent</TableHeaderColumn>
      </BootstrapTable>
    </div>


    return(
        <div>
            <div className="center">
                {content}
            </div>
        </div>
    );
  }
}
export default FetchCustomerTable

2 个答案:

答案 0 :(得分:1)

好吧,这是给正在阅读本文的人的。我可以通过删除多余的不必要的状态“值”来解决我的问题。我选择了FormControl,并让用户从预定义页面大小的列表中进行选择,而不是键入页面大小。该选择器的名称为“ limit”,与表示页面大小的状态名称相同。我有一个处理程序,只要选择了select中的一个选项,便会更新此状态。

答案 1 :(得分:0)

您可以在componentWillReceiveProps组件的React生命周期中使用Child
https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/component_will_receive_props.html