首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MUI-Datatable,子组件检测父组件状态的变化。

MUI-Datatable,子组件检测父组件状态的变化。
EN

Stack Overflow用户
提问于 2021-02-26 20:07:19
回答 1查看 1.1K关注 0票数 0

我从反应开始,这个问题使我睡不着觉。

据我所知,状态(this.state)只能在创建它的组件中访问,但在我的项目中,这种情况并没有发生。子组件能够识别对父组件的状态所做的更改,这减缓了我的应用程序,让我尝试用代码更好地解释它:

在父组件中,我呈现页面标题,这是一个添加新记录的模式,并包括负责组装datatable的子组件(由MUI提供的Datatable和通过API加载的数据):

https://github.com/gregnb/mui-datatables

父组件:

代码语言:javascript
复制
import React from 'react';
import Typography from '@material-ui/core/Typography';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import Button from '@material-ui/core/Button';

// Components
import CadcliFieldContent from './CadcliFieldContent';

class CadcliField extends React.Component {

    state = {
        isLoading: false,
        isNew: true,
        dialog: false,
        formData: {
            name: 'Test'
        }
    };

    openDialog = () => { this.setState({ dialog: true }); }
    closeDialog = () => { this.setState({ dialog: false }); }
    formDataChange = name => event => {        
        var formDataTemp = this.state.formData;      
        formDataTemp[name] = event.target.value;
        this.setState({ formData: formDataTemp });
    };

    render () {

        return (
            <div className="flex flex-1 w-full">

                <div className="flex items-center justify-end">
                    <Button
                        className="normal-case"
                        variant="contained" 
                        color="secondary"
                        role="button"
                        onClick={this.openDialog}
                    >
                        <Icon>add</Icon>
                        <span className="mx-1">{t('NEW_FIELD')}</span>
                    </Button>
                </div>
                            
                <CadcliFieldContent 
                    urlBase="cadcli-field/" 
                />
                
                <Dialog
                    className='max-w-lg w-full m-24'
                    onClose={this.closeDialog}
                    open={this.state.dialog}
                >
                    <DialogTitle component="div" className="p-0">
                        <Typography className="text-16 ml-8">Fields</Typography>
                    </DialogTitle>
                    <DialogContent className="p-16 sm:p-24">
                        <div className="flex items-center mb-24">
                            <TextField
                                type="text"
                                name="name"
                                id="input-name"
                                value={formData.name}
                                onChange={this.formDataChange('name')}
                                variant="outlined"
                                fullWidth
                                required
                            />
                        </div>
                    </DialogContent>

                </Dialog>
            </div>
        );
    };
}

export default CadcliField;

子组件

代码语言:javascript
复制
import React from 'react';
import axios from 'axios';
import MUIDataTable from "mui-datatables";
import { CircularProgress, Typography } from '@material-ui/core';

class CadcliContent extends React.Component {
    state = {
        urlApi: process.env.REACT_APP_API_URL, 
        page: 0,
        count: 1,
        rowsPerPage: 10,
        denseTable: true,
        idDeleteModal: 0,
        sortOrder: {},
        filter: {},
        search: '',
        data: [['Loading...']],
        columns: [
            {name: 'id', label: this.props.t('utils:ACTIONS')},
            {name: 'id', label: 'ID', options: { filterType : 'textField' }},           
        ],
        isLoading: false,
    };

    componentDidMount() {
        this.getData(this.state.urlApi, 0);
    }

    // get data
    getData = async (url, page) => {
        this.setState({ isLoading: true });
        const res = await this.axiosRequest(url, page);
        this.setState({ data: res.data, isLoading: false, count: res.total });
    };

    axiosRequest = (url, page, sortOrder = {}, filter = {}, searchText = '') => {

        url = url + '?page_size=' + this.state.rowsPerPage;
        url += '&page=' + (page + 1);   

        // Ordering
        if (sortOrder.name !== undefined) {
            if (sortOrder.direction === 'asc') {
                url += '&ordering=' + sortOrder.name;
            } else {
                url += '&ordering=-' + sortOrder.name;
            }
        }

        // Filtering
        if (filter.length > 0) {
            var columnsTable = this.state.columns;
            filter.forEach(function(value, key){
                if (value.length > 0) {
                    url += '&' + columnsTable[key].name + '=' + value;
                }
            });
        }

        // Generic Searching
        if (searchText !== "" && searchText !== null) {
            url += '&search=' + searchText;
        }
        
        return new Promise((resolve, reject) => {
            axios
            .get(url)
            .then(response => {
                resolve({
                    data: response.data.results,
                    page: page,
                    total: response.data.count,
                });
            }).catch(function (error) {
                resolve({
                    data: [],
                    page: 0,
                    total: 0,
                });
            });
        });
    };

    sort = (page, sortOrder, filter) => {
        this.setState({ isLoading: true });
        this.axiosRequest(this.state.urlApi, page, sortOrder, filter).then(res => {
            this.setState({
                data: res.data,
                page: res.page,
                sortOrder,
                filter,
                isLoading: false,
                count: res.total,
            });
        });
    };
        
    changePage = (page, sortOrder, filter) => {
        this.setState({
            isLoading: true,
        });

        this.axiosRequest(this.state.urlApi, page, sortOrder, filter).then(res => {
            this.setState({
                isLoading: false,
                page: res.page,
                sortOrder,
                filter,
                data: res.data,
                count: res.total,
            });
        });
    };

    filterChange = (page, sortOrder, filter) => {
        this.setState({
            isLoading: true,
        });

        this.axiosRequest(this.state.urlApi, page, sortOrder, filter).then(res => {
            this.setState({
                isLoading: false,
                page: res.page,
                sortOrder,
                filter,
                data: res.data,
                count: res.total,
            });
        });
    };

    searchTable = (page, sortOrder, columnsFilter, searchText) => {
        this.setState({
            isLoading: true,
        });
        
        this.axiosRequest(this.state.urlApi, page, sortOrder, columnsFilter, searchText).then(res => {
            this.setState({
                isLoading: false,
                page: res.page,
                sortOrder,
                filter: columnsFilter,
                search: searchText,
                data: res.data,
                count: res.total,
            });
        });
        
    }

    render() {
    
        const { data, count, isLoading, rowsPerPage, sortOrder } = this.state;

        const options = {
            filter: true,
            filterType: 'dropdown',
            responsive: 'vertical',         
            serverSide: true,
            download: false,
            count: count,
            rowsPerPage: rowsPerPage,
            rowsPerPageOptions: [],
            sortOrder: sortOrder,
            resizableColumns: false,
            confirmFilters: true,               
            onTableChange: (action, tableState) => {    
                switch (action) {                   
                    case 'changePage':
                        this.changePage(tableState.page, tableState.sortOrder, tableState.filterList);
                        break;
                    case 'sort':
                        this.sort(tableState.page, tableState.sortOrder, tableState.filterList);
                        break;
                    case 'search':
                        this.searchTable(tableState.page, tableState.sortOrder, tableState.filterList, tableState.searchText);
                        break;
                    default:
                        console.log('[' + action + '] action not handled.');
                }
            },      
            setTableProps: () => {
                return {
                    size: this.state.denseTable ? 'small' : 'medium'
                };
            },
        };

        return (
            <div className="w-full flex flex-col">
                <MUIDataTable
                    title={
                        <Typography variant="h6">
                            Listing
                            {isLoading && <CircularProgress size={24} />}
                        </Typography>
                    }
                    data={data}
                    columns={this.state.columns}
                    options={options}
                />
            </div>  
        );
    
    }
}

export default CadcliContent;

发生了什么:

每次更改父组件中的状态时(例如,键入TextField并更改this.state.formData.name属性),或单击按钮打开MUI数据表的onTableChange函数(change this.state.dialog),就会触发并在表中生成处理,因为我放置了一个console.log ()通知:

代码语言:javascript
复制
onTableChange: (action, tableState) => {    
    switch (action) {                   
        /* .... */
        default:
            console.log('[' + action + '] action not handled.');
    }
},   

(摘自触发console.log的代码)

这让我感到不安,因为MUI-Datatable明白它已经改变了this.state中的某些内容,并且进行了非常繁重的处理,甚至在延迟的输入中保留了输入的处理。

知道会发生什么事吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-05 16:47:44

解决方案比我想象的要简单,我最终通过研究和理解反应状态概念来解决这个问题。

尽管我仍然不明白MUI-Datables组件是如何观察到整个状态的,但是将Dialog封装在一个新组件中的简单事实,以及一个新的孤立状态,都发生了奇迹。

因此,如果有人遇到同样的问题,解决办法是:

CadcliField.js

代码语言:javascript
复制
<CadcliFieldContent 
    urlBase="cadcli-field/" 
   {...this.props}
/>

<CadcliFieldFormNew 
    isNew={this.state.isNew}
    dialog={this.state.dialog}
    closeDialog={this.closeDialog}
/>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66392182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档