我有以下反应组件:
class Statuses extends React.Component {
constructor(props) {
super();
this.groups = props.groups;
this.state = {
statuses: [],
editDialog: null,
deleteDialog: null,
editTransitionsDialog: null,
transitions: null,
editTransitionGroupsDialog: null,
transition: null,
groups: null,
alert: null,
};
}
componentDidMount() {
this.fetchStatuses();
}
handleCloseAlert = () => {
let alertType = this.props.alert.type;
this.props.cleanCatalogsMessage();
if (alertType == ALERT_SUCCESS) {
this.setState({editDialog: null});
}
}
TransitionRight = (props) => {
return <Slide {...props} direction="right" />;
}
fetchStatuses = () => {
this.props.fetchStatuses(this.props.currentForm.id)
}
handleEditClick = (id) => {
if (id) {
this.setState({editDialog: this.props.statuses.find(status => status.id === id)});
} else {
this.setState({editDialog: {id: null, name: null, description: null, color: '#808080'}})
}
}
handleCloseEditDialog = (proceed) => {
if (proceed) {
this.saveStatus();
} else {
this.setState({editDialog: null});
};
}
handleEditStatusChange = (e) => {
let newEditDialog = Object.assign({}, this.state.editDialog)
switch (e.target.name) {
case 'status_name': {
newEditDialog.name = e.target.value;
break;
}
case 'status_description': {
newEditDialog.description = e.target.value;
break;
}
case 'status_slug': {
newEditDialog.slug = e.target.value;
break;
}
case 'status_color': {
newEditDialog.color = e.target.value;
break;
}
default: {
alert("Error on handleEditTransitionChange");
}
}
this.setState({editDialog: newEditDialog});
}
saveStatus = () => {
if (this.state.editDialog.id) {
this.updateStatus();
} else {
this.createStatus();
}
}
updateStatus = () => {
this.props.updateStatus(this.state.editDialog);
}
createStatus = () => {
// const requestString = backendServer + 'api/general/statuses/';
const form = {
automat: this.props.currentForm.id,
name: this.state.editDialog.name,
description: this.state.editDialog.description,
slug: this.state.editDialog.slug,
color: this.state.editDialog.color,
}
this.props.createStatus(form);
}
handleDeleteClick = (id) => {
this.setState({deleteDialog: this.state.statuses.find(status => status.id === id)});
}
handleCloseDeleteDialog = (proceed) => {
if (proceed) {
this.deleteStatus()
} else {
this.setState({deleteDialog: null});
}
}
deleteStatus = () => {
const requestString = backendServer + 'api/general/statuses/' + this.state.deleteDialog.id + '/';
axios.delete(requestString, getAuthHeader())
.then((Response) => {
let newStatusesList = this.state.statuses.slice();
let i = newStatusesList.findIndex((status) => status.id === this.state.deleteDialog.id);
newStatusesList.splice(i, 1);
newStatusesList.forEach((status) => {
let j = status.transitions.findIndex((transition) => transition.id === this.state.deleteDialog.id)
if (j > -1) {
status.transitions.splice(j, 1);
}
})
this.setState({statuses: newStatusesList, deleteDialog: null, alert: "¡El estado se ha eliminado con Éxito!"});
})
.catch((Error) => {
const message = getErrorMessage(Error).message.message;
alert(message)
})
}
handleEditTransitionsClick = (id) => {
let statusToEdit = this.props.statuses.find(status => status.id === id)
this.setState({
editTransitionsDialog: statusToEdit,
transitions: statusToEdit.transitions.slice()
});
}
handleEditTransitionsChange = (e) => {
let newTransitionsList = null;
if (e.target.checked) {
newTransitionsList = this.state.transitions.slice();
let statusToAdd = this.props.statuses.find((status) => status.name === e.target.name);
let transitionToAdd = {id: statusToAdd.id, name: statusToAdd.name};
newTransitionsList.push(transitionToAdd);
} else {
newTransitionsList = this.props.transitions.slice();
let i = newTransitionsList.findIndex((transition) => transition.name === e.target.name);
if (i > -1) {
newTransitionsList.splice(i, 1);
}
}
this.setState({transitions: newTransitionsList});
}
handleCloseEditTransitionsDialog = (proceed) => {
if (proceed) {
this.updateTransitions();
} else {
this.setState({editTransitionsDialog: null, transitions: null});
}
}
updateTransitions = () => {
let transitionsToAdd = this.state.transitions.filter(transition => !this.state.editTransitionsDialog.transitions.includes(transition));
let transitionsToDelete = this.state.editTransitionsDialog.transitions.filter(transition => !this.state.transitions.includes(transition));
const requestString = backendServer + 'api/general/set_transitions/' + this.state.editTransitionsDialog.id + '/';
axios.post(requestString, {add: transitionsToAdd, delete: transitionsToDelete}, getAuthHeader())
.then((Response) => {
let newEditTransitionsDialog = Object.assign({}, this.state.editTransitionsDialog);
transitionsToAdd.forEach((transition) => {
newEditTransitionsDialog.transitions.push({id: transition.id, name: transition.name, groups: []});
})
transitionsToDelete.forEach((transition) => {
let i = newEditTransitionsDialog.transitions.findIndex((transitionToEval) => transitionToEval.id === transition.id);
newEditTransitionsDialog.transitions.splice(i, 1);
})
let newStatusesList = this.state.statuses.slice();
let j = newStatusesList.findIndex((status) => status.id === this.state.editTransitionsDialog.id);
newStatusesList[j] = newEditTransitionsDialog;
this.setState({statuses: newStatusesList, editTransitionsDialog: null, transitions: null, alert: "¡Las transiciones se modificaron con éxito!"});
})
.catch((Error) => {
const message = getErrorMessage(Error).message.message;
alert(message)
})
}
handleEditTransitionGroupsClick = (id, transition) => {
let newEditTransitionGroupsDialog = Object.assign({}, this.props.statuses.find((status) => status.id === id));
let newTransition = Object.assign({}, newEditTransitionGroupsDialog.transitions.find((transitionToEval) => transitionToEval.id === transition));
this.setState({editTransitionGroupsDialog: newEditTransitionGroupsDialog, transition: newTransition, groups: newTransition.groups.slice()});
}
handleEditTransitionGroupsChange = (e) => {
let newGroupsList = this.state.groups.slice();
if (e.target.checked) {
let newGroup = this.groups.find((group) => group.name === e.target.name);
newGroupsList.push({id: newGroup.id, name: newGroup.name});
} else {
let i = this.groups.findIndex((group) => group.name === e.target.name);
newGroupsList.splice(i, 1);
}
this.setState({groups: newGroupsList});
}
handleCloseEditTransitionGroupsDialog = (proceed) => {
if (proceed) {
this.updateGroups();
} else {
this.setState({editTransitionGroupsDialog: null, transition: null, groups: null});
}
}
updateGroups = () => {
let groupsToAdd = this.state.groups.filter(group => !this.state.transition.groups.includes(group));
let groupsToDelete =this.state.transition.groups.filter(group => !this.state.groups.includes(group));
const requestString = backendServer + 'api/general/set_groups/' + this.state.transition.id + '/';
axios.post(requestString, {automat: this.props.currentForm.id, init_status: this.state.editTransitionGroupsDialog.id, final_status: this.state.transition.id, add: groupsToAdd, delete: groupsToDelete}, getAuthHeader())
.then((Response) => {
let newTransition = Object.assign({}, this.state.transition);
newTransition.groups = this.state.groups.slice()
let newStatus = Object.assign({}, this.state.editTransitionGroupsDialog);
let i = newStatus.transitions.findIndex(transition => transition.id === newTransition.id);
newStatus.transitions[i] = newTransition;
let newStatusesList = this.state.statuses.slice();
i = newStatusesList.findIndex(status => status.id === newStatus.id);
newStatusesList[i] = newStatus;
this.setState({
statuses: newStatusesList,
editTransitionGroupsDialog: null,
transition: null,
groups: null,
alert: "¡Los Grupos se modificaron con éxito!"
});
})
.catch((Error) => {
const message = getErrorMessage(Error).message.message;
alert(message);
})
}
StatusSnackbars = () => {
const classes = useStylesStatusSnackBars();
const [open, setOpen] = React.useState(false);
const handleClick = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setOpen(false);
};
return (
<div className={classes.root}>
<Button variant="outlined" onClick={handleClick}>
Open success snackbar
</Button>
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
This is a success message!
</Alert>
</Snackbar>
<Alert severity="error">This is an error message!</Alert>
<Alert severity="warning">This is a warning message!</Alert>
<Alert severity="info">This is an information message!</Alert>
<Alert severity="success">This is a success message!</Alert>
</div>
);
}
StatusesTable = () => {
return (
<div width="100%">
{this.props.statuses && this.props.statuses.map((status) => {
return (<this.StatusEntry status={status} />)
})}
</div>
)
}
StatusEntry = (status) => {
const classes = useStylesStatusEntry();
return (
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<div style={{paddingRight: "5px"}}>
<Chip label={"[" + status.status.id + "]" + status.status.name} size="large" style={{color: "white", backgroundColor: status.status.color}}/>
</div>
<Typography className={classes.secondaryHeading}>{status.status.description}</Typography>
</AccordionSummary>
<AccordionDetails>
<div>
<div style={{display: "flex", alignContent: "center", paddingBottom: "10px"}}>
<div style={{paddingRight: "5px"}}><Button color="primary" variant="contained" size="small" onClick={() => this.handleEditClick(status.status.id)}>Editar</Button></div>
<div style={{paddingRight: "5px"}}><Button color="primary" variant="contained" size="small" onClick={() => this.handleEditTransitionsClick(status.status.id)}>Transiciones</Button></div>
<div style={{paddingRight: "5px"}}><Button color="secondary" variant="contained" size="small" onClick={() => this.handleDeleteClick(status.status.id)}>Eliminar</Button></div>
</div>
<div>
{status.status.transitions.map((transition) => (
<div>
<IconButton aria-label="groups" size="small" color="primary" onClick={() => this.handleEditTransitionGroupsClick(status.status.id, transition.id)}>
<EditIcon fontSize="inherit" />
</IconButton>
<Chip label={transition.name} size="small" style={{color: transition.color}} variant="outlined"/>
{transition.groups.map((group => (
<Chip label={group.name} size="small" variant="outlined" />
)))}
<div fullwidth style={{paddingBottom: "5px", paddingTop: "5px"}}><Divider /></div>
</div>
))}
</div>
</div>
</AccordionDetails>
</Accordion>
)
}
render() {
const getFinalStatusChip = () => {
let finalStatus = this.props.statuses.find((status) => status.id === this.state.transition.id)
return (
<Chip label={finalStatus.name} size="large" style={{color: "white", backgroundColor: finalStatus.color}} />
)
}
return (
<div>
<div style={{display: 'flex', paddingBottom: '5px'}}>
<div className="col-10" style={{paddingTop: '5px'}}>
<h1>Estados: {this.props.currentForm.name}</h1>
</div>
<div className="col-2">
<Fab size="small" color="primary" aria-label="add" onClick={() => this.handleEditClick(null)}>
<AddIcon />
</Fab>
</div>
</div>
<this.StatusesTable/>
{this.state.editDialog && !this.props.showMessage &&
<Dialog open={this.state.editDialog !== null} aria-labelledby="edit-dialog-title">
{this.state.editDialog.id?
<DialogTitle id="edit-dialog-title">Editar Estado: [{this.state.editDialog.id}]{this.state.editDialog.name}</DialogTitle>:
<DialogTitle id="edit-dialog-title">Crear Estado: [ ] Nuevo Estado</DialogTitle>
}
<DialogContent>
<TextField
autoFocus
margin="dense"
id="status-name"
name="status_name"
label="Nombre"
fullWidth
value={this.state.editDialog.name}
onChange={this.handleEditStatusChange}
/>
<TextField
margin="dense"
id="status-description"
name="status_description"
label="Descripción"
fullWidth
multiline={true}
rows={4}
value={this.state.editDialog.description}
onChange={this.handleEditStatusChange}
/>
<TextField
margin="dense"
id="status_slug"
name="status_slug"
label="Slug"
fullWidth
multiline={false}
value={this.state.editDialog.slug}
onChange={this.handleEditStatusChange}
/>
<div style={{paddingTop: "10px"}}>
<p style={{color: "gray"}}>Color</p>
<CompactPicker
color={this.state.editDialog.color}
onChangeComplete={(color) => this.handleEditStatusChange({target: {name: "status_color", value: color.hex}})
}
/>
</div>
</DialogContent>
<DialogActions>
<Button onClick={() => this.handleCloseEditDialog(false)} color="primary">
Cancelar
</Button>
<Button onClick={() => this.handleCloseEditDialog(true)} color="primary">
Aceptar
</Button>
</DialogActions>
</Dialog>
}
{this.state.deleteDialog &&
<Dialog open={this.state.deleteDialog !== null} aria-labelledby="delete-dialog-title">
<DialogTitle id="delete-dialog-title">Eliminar Estado: [{this.state.deleteDialog.id}]{this.state.deleteDialog.name}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
<div style={{color: 'black'}}>
<span>¿Está seguro de que desea eliminar este Estado:?</span>
<div>
<Chip label={this.state.deleteDialog.name} size="large" style={{color: "white", backgroundColor: this.state.deleteDialog.color}} />
</div>
</div>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button color="primary" onClick={() => this.handleCloseDeleteDialog(true)}>
Aceptar
</Button>
<Button color="primary" autoFocus onClick={() => this.handleCloseDeleteDialog(false)}>
Cancelar
</Button>
</DialogActions>
</Dialog>
}
{this.state.editTransitionsDialog &&
<Dialog aria-labelledby="edit-transitions-dialog-title" open={this.state.editTransitionsDialog !== null}>
<DialogTitle id="edit-transitions-dialog-title">Editar Transiciones</DialogTitle>
<DialogContent dividers>
<div>
<Chip label={this.state.editTransitionsDialog.name} size="large" style={{color: "white", backgroundColor: this.state.editTransitionsDialog.color}} />
</div>
<div>
<FormGroup row>
{this.props.statuses.map((status) => {
return (
<FormControlLabel
control={
<Checkbox
checked={this.state.transitions.find((transition) => transition.id === status.id)}
name={status.name}
color="primary"
onChange={this.handleEditTransitionsChange}
/>
}
label={status.name}
/>
)
})}
</FormGroup>
</div>
</DialogContent>
<DialogActions>
<Button color="primary" onClick={() => this.handleCloseEditTransitionsDialog(true)}>
Aceptar
</Button>
<Button color="primary" autoFocus onClick={() => this.handleCloseEditTransitionsDialog(false)}>
Cancelar
</Button>
</DialogActions>
</Dialog>
}
{this.state.editTransitionGroupsDialog &&
<Dialog aria-labelledby="edit-transition-groups-dialog-title" open={this.state.editTransitionGroupsDialog !== null}>
<DialogTitle id="edit-transition-groups-dialog-title">Editar Grupos</DialogTitle>
<DialogContent dividers>
<div>
<Chip label={this.state.editTransitionGroupsDialog.name} size="large" style={{color: "white", backgroundColor: this.state.editTransitionGroupsDialog.color}} />
<ArrowRightIcon />
{getFinalStatusChip()}
</div>
<div>
<FormGroup row>
{this.groups.map((group) => {
return (
<FormControlLabel
control={
<Checkbox
name={group.name}
color="primary"
checked={this.state.groups.find((groupToEval) => groupToEval.id === group.id)}
onChange={this.handleEditTransitionGroupsChange}
/>
}
label={group.name}
/>
)
})}
</FormGroup>
</div>
</DialogContent>
<DialogActions>
<Button color="primary" onClick={() => this.handleCloseEditTransitionGroupsDialog(true)}>
Aceptar
</Button>
<Button color="primary" autoFocus onClick={() => this.handleCloseEditTransitionGroupsDialog(false)}>
Cancelar
</Button>
</DialogActions>
</Dialog>
}
{this.props.showMessage &&
<AttrAlert
displayCase="alert_dialog"
type={this.props.alert.type}
message={this.props.alert.message}
handleCloseAlert={this.handleCloseAlert}
/>}
</div>
)
}
}
const mapStateToProps = ({auth, catalogs}) => {
const {groups} = auth;
const {statuses, alert, showMessage} = catalogs;
return {groups, statuses, alert, showMessage};
}
const mapDispatchToProps = {
fetchStatuses,
createStatus,
updateStatus,
cleanCatalogsMessage
}
export default connect(mapStateToProps, mapDispatchToProps)(Statuses);
组件中出现错误StatusesTable
。我已经调试并发现它this.StatusEntry
永远不会执行,因为我在其中设置了一个断点,并且它永远不会到达,即使总是到达调用它的行中的断点也是如此。
所以StatusEntry
永远不会执行,但在地图循环结束时会引发错误。这是我在检查器控制台中遇到的错误:
Error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
这是错误的完整信息:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
只有在节点版本为 10.19.0 的服务器中从缩小代码运行应用程序时才会出现此错误,但当从常规 JS 代码和节点版本 14.15.3 在本地运行时,它可以完美运行。