Компонент React и Apollo Client не работает «в режиме реального времени» - PullRequest
1 голос
/ 24 сентября 2019

Я пытаюсь создать пользовательскую систему, но я что-то путаю, потому что она не работает в реальном времени.

Я создал пример Песочница , чтобы показать мою проблему"и мой код.Я не добавил никаких проверок, это только для примера.

Вот некоторые из проблем (я вижу):

  1. Действия кнопки запускаются при втором нажатии
  2. Данные не будут обновляться после создания / удаления.

Это компонент <UsersPage />:

import React, { Fragment, useState, useEffect } from "react";
import { useMutation, useLazyQuery } from "@apollo/react-hooks";
import { ADD_USER, LIST_USERS, DELETE_USER } from "../../../config/constants";
import { useSnackbar } from "notistack";
import {
  Grid,
  Paper,
  TextField,
  Button,
  Typography,
  MenuItem,
  FormHelperText
} from "@material-ui/core";
import AddUserIcon from "@material-ui/icons/PersonAdd";
import { withStyles } from "@material-ui/core/styles";
import PropTypes from "prop-types";
import Table from "../../Table";

const styles = theme => ({
  grid: {
    margin: theme.spacing(3)
  },
  icon: {
    marginRight: theme.spacing(2)
  },
  form: {
    width: "100%",
    marginTop: theme.spacing(3),
    overflowX: "auto",
    padding: theme.spacing(2)
  },
  submit: {
    margin: theme.spacing(2)
  },
  container: {
    display: "flex",
    flexWrap: "wrap"
  },
  textField: {
    marginLeft: theme.spacing.unit,
    marginRight: theme.spacing.unit
  },
  root: {
    width: "100%",
    marginTop: theme.spacing(3),
    overflowX: "auto",
    padding: theme.spacing(2)
  },
  title: {
    margin: theme.spacing(2)
  },
  table: {
    minWidth: 700
  },
  noRecords: {
    textAlign: "center"
  },
  button: {
    margin: theme.spacing.unit
  }
});

const Users = props => {
  const [idState, setIdState] = useState(null);
  const [emailState, setEmailState] = useState("");
  const [passwordState, setPasswordState] = useState("");
  const [usersState, setUsersState] = useState([]);
  const [errorsState, setErrorsState] = useState({});
  const [loadingState, setLoadingState] = useState(false);
  const [addUser, addUserResponse] = useMutation(ADD_USER);
  const [loadUsers, usersResponse] = useLazyQuery(LIST_USERS);
  const [deleteUser, deleteUserResponse] = useMutation(DELETE_USER);
  const { enqueueSnackbar } = useSnackbar();

  useEffect(() => {
    loadUsers();

    if (usersResponse.called && usersResponse.loading) {
      setLoadingState(true);
    } else if (usersResponse.called && !usersResponse.loading) {
      setLoadingState(false);
    }

    if (usersResponse.data) {
      setUsersState(usersResponse.data.getUsers);
    }
  }, [usersResponse.called, usersResponse.loading, usersResponse.data]);

  function handleSubmit(e) {
    e.preventDefault();

    if (idState) {
    } else {
      addUser({
        variables: {
          email: emailState,
          password: passwordState
        }
      });
    }

    if (addUserResponse.called && addUserResponse.loading) {
      enqueueSnackbar("Creating user");
    }

    if (addUserResponse.error) {
      addUserResponse.error.graphQLErrors.map(exception => {
        const error = exception.extensions.exception;
        const messages = Object.values(error);
        enqueueSnackbar(messages[0], { variant: "error" });
      });
    }

    if (addUserResponse.data && addUserResponse.data.addUser) {
      enqueueSnackbar("user created", { variant: "success" });
      loadUsers();
    }
  }

  function handleEdit(user) {
    setIdState(user.id);
    setEmailState(user.email);
  }

  async function handleDelete(data) {
    if (typeof data === "object") {
      data.map(id => {
        deleteUser({ variables: { id } });
        if (deleteUserResponse.data && deleteUserResponse.data.deleteUser) {
          enqueueSnackbar("User deleted", { variant: "success" });
        }
      });
    } else {
      deleteUser({ variables: { id: data } });
      if (deleteUserResponse.data && deleteUserResponse.data.deleteUser) {
        enqueueSnackbar("User deleted", { variant: "success" });
      }
    }
  }

  function resetForm() {
    setIdState(null);
    setEmailState("");
  }
  const { classes } = props;

  return (
    <Fragment>
      <Grid container spacing={8}>
        <Grid item xs={3} className={classes.grid}>
          <Paper className={classes.form}>
            <Typography variant="h6" className={classes.title}>
              {idState ? `Edit user: ${emailState}` : "Create user"}
            </Typography>
            <form className={classes.container} onSubmit={handleSubmit}>
              <input type="hidden" name="id" value={idState} />
              <TextField
                className={classes.textField}
                label="E-mail address"
                type="email"
                variant="outlined"
                margin="normal"
                autoComplete="email"
                id="email"
                name="email"
                required={!idState}
                fullWidth
                onChange={e => setEmailState(e.target.value)}
                value={emailState}
                aria-describedby="email-error"
              />
              <FormHelperText id="email-error">
                {errorsState.email}
              </FormHelperText>
              <TextField
                className={classes.textField}
                label="Password"
                variant="outlined"
                margin="normal"
                autoComplete="password"
                id="password"
                name="password"
                required={!idState}
                type="password"
                fullWidth
                onChange={e => setPasswordState(e.target.value)}
                value={passwordState}
                aria-describedby="password-error"
              />
              <FormHelperText id="password-error">
                {errorsState.password}
              </FormHelperText>

              <Button
                variant="contained"
                color="primary"
                className={classes.submit}
                size="large"
                type="submit"
              >
                <AddUserIcon className={classes.icon} /> Save
              </Button>
              <Button
                variant="contained"
                color="secondary"
                className={classes.submit}
                type="button"
                onClick={resetForm}
              >
                <AddUserIcon className={classes.icon} /> Add new
              </Button>
            </form>
          </Paper>
        </Grid>
        <Grid item xs={8} className={classes.grid}>
          <Paper className={classes.root}>
            <Table
              data={usersState}
              className={classes.table}
              columns={{
                id: "ID",
                email: "E-mail address"
              }}
              classes={classes}
              title="Users"
              handleEdit={handleEdit}
              handleDelete={handleDelete}
              filter={true}
              loading={loadingState}
            />
          </Paper>
        </Grid>
      </Grid>
    </Fragment>
  );
};

Users.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(styles)(Users);

В случае, если вам нужно больше кода или редактирования:

Песочница веб-интерфейса: Приложение / Код

Песочница бэкэнда: Приложение / Код

Любые комментарии, предложения или что-то будет оценено.

...