Reactjs 仅当父组件';s按钮“提交”被单击两次

Reactjs 仅当父组件';s按钮“提交”被单击两次,reactjs,jsx,Reactjs,Jsx,我有两个组件,我有这个问题。父组件CustomerTableTools将表(页面)的大小发送给子组件(FetchCustomerTable)。当我单击“提交”时,父对象的状态将更改,但除非我单击“提交”两次,否则子对象将不会重新渲染。输入和提交按钮位于父级内部,表位于子级内部。我遗漏了一个重要的细节吗?我认为如果父对象将其状态作为道具发送给子对象,并且状态发生了变化,则子对象应该重新渲染 表的数据由this.props.customers填充 谢谢大家抽出时间。我只想学习,我感谢你的投入,谢谢

我有两个组件,我有这个问题。父组件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
//***************************
//CustomerTableTools(父级):
//****************************
从“React”导入React,{Component};
从“./FetchCustomerTable”导入FetchCustomerTable
从“../Util/LoadingSpinner”导入LoadingSpinner
从“../Util/ErrorStatus”导入ErrorStatus
从“axios/index”导入axios;
类CustomerTableTools扩展组件{
建造师(道具){
超级(道具);
此.state={
错误:,
页码:0,
限额:10,
数值:10,
客户:[],
};
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
log(“props:+JSON.stringify(props))
}
手变(活动){
如果(event.target.value>=0&(!isNaN(event.target.value)&&
(函数(x){return(x | 0)==x;})(parseFloat(event.target.value))){
this.setState({value:event.target.value});
}
}
componentDidMount(){
this.setState({limit:this.state.value,limitChanged:true});
log(“获取数据1”);
this.setState({loading:true,statusMessage:});
axios.get(“http://localhost:8090/customer/viewCustomers/", {
参数:{
页面:this.state.page,
限制:this.state.limit
}
})
。然后(响应=>{
//log(“响应:+JSON.stringify(response.data));
这是我的国家({
客户:response.data.content,
statusMessage:null,
加载:错误
});
console.log(this.state.customers);
})
.catch(错误=>{
console.log(错误);
这是我的国家({
状态消息:,
})
}
);
}
handleSubmit(事件){
event.preventDefault();
this.setState({limit:this.state.value,limitChanged:true});
console.log(“==HANDLE SUBMIT===”);
this.setState({loading:true,statusMessage:});
axios.get(“http://localhost:8090/customer/viewCustomers/", {
参数:{
页面:this.state.page,
限制:this.state.limit
}
})
。然后(响应=>{
//log(“响应:+JSON.stringify(response.data));
这是我的国家({
客户:response.data.content,
statusMessage:null,
加载:错误
});
console.log(this.state.customers);
})
.catch(错误=>{
console.log(错误);
这是我的国家({
状态消息:,
})
}
);
}
render(){
设tableBody=null;
表体=
返回(
页面大小:
{表体}
);
}
}
导出默认CustomerTableTools
//***************************
//FetchCustomerTable(子项):
//***************************
从“React”导入React,{Component};
从“axios”导入axios;
导入“../App.css”
从“../Util/LoadingSpinner”导入LoadingSpinner
从“../Util/ErrorStatus”导入ErrorStatus
从“react-react”导入{BootstrapTable,TableHeaderColumn,ClearSearchButton}
引导表';
从“react bootstrap”导入{按钮,Glyphicon}
类FetchCustomerTable扩展组件{
onAfterSaveCell(行){
const customerId=行['customerId'];
axios({
方法:'放',
网址:`http://localhost:8090/customer/updateCustomer/${customerId}`,
数据:JSON.stringify(行),
标题:{'Content-Type':'application/json;charset=utf-8'}
})
。然后((响应)=>{
控制台日志(响应);
console.log(response.data);
})
.catch((错误)=>{
console.log(错误);
//记录器错误(error);
});
}
handleDeletedRow(行键){
log(“删除的键:+rowKeys”);
axios({
方法:“删除”,
网址:`http://localhost:8090/customer/deleteCustomers/${rowKeys}`,
数据:行键,
标题:{'Content-Type':'application/json;charset=utf-8'}
})
。然后((响应)=>{
控制台日志(响应);
console.log(response.data);
})
.catch((错误)=>{
console.log(错误);
//记录器错误(error);
});
}
//表格顶部的样式删除按钮
customDeleteButton=(onBtnClick)=>{
返回(
删除
挑选出来的
);
}
onSearchChange=(搜索文本)=>{
log(“内部搜索更改!”);
this.setState({searchText:searchText});
}
handleClearButtonClick=(onClick)=>{
如果(!!this.state.searchText){
log(“获取数据2”);
//this.setState({loading:true,statusMessage:});
axios.get(“http://localhost:8090/customer/searchResults/", {
参数:{
名字:this.state.searchText,
电子邮件:this.state.searchText,
佩奇:这是道具