Реагировать - Очистить форму после отправки с управлением состоянием Context API - PullRequest
0 голосов
/ 24 марта 2020

У меня есть простой Expense Tracker с формой для добавления транзакций в серверную часть mongoDB. Я использую контекстные API и материальные элементы пользовательского интерфейса. Я не могу понять, как очистить текстовые поля после запуска onSubmit, но я очень плохо знаком с React и Javascript в целом. Я видел несколько других постов о создании функции для запуска с помощью кнопки onClick, но я не уверен, что это правильный путь, так как у меня есть «initialState» в моем глобальном контексте. Я также видел другие маршруты, которые использовали appReducer для этого, но я не мог понять, как это применить. Чтобы быть понятным, я хочу, чтобы это очистить форму на Submmit, а не кнопку, чтобы нажать «очистить поля». Ниже мой код:

Компонент формы

import React, { useState, useContext } from "react";
import { GlobalContext } from "../context/GlobalState";

// UI for Text Field
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import Grid from "@material-ui/core/Grid";

// UI and utils for date picker
import "date-fns";
import DateFnsUtils from "@date-io/date-fns";
import {
  MuiPickersUtilsProvider,
  KeyboardDatePicker
} from "@material-ui/pickers";

const useStyles = makeStyles(theme => ({
  root: {
    "& > *": {
      align: "center",
      margin: theme.spacing(1),
      width: 200,
      flexgrow: 1
    }
  },
  textfield: {
    height: 38
  },
  button: {
    height: 38,
    align: "center"
  },
  grid: {
    fullwidth: true,
    direction: "row",
    justify: "center",
    alignItems: "center",
    display: "flex",
    flexDirection: "column",
    justifyContent: "center"
  }
}));

export const AddTransaction = () => {
  const classes = useStyles();

  const [transactionDate, setTransactionDate] = useState(new Date());
  const [text, setText] = useState('');
  const [amount, setAmount] = useState(0);

  const { addTransaction } = useContext(GlobalContext);


  const onSubmit = e => {
    e.preventDefault();

    const newTransaction = {
      transactionDate,
      text,
      amount: +amount
    };

    addTransaction(newTransaction);
  };

  return (
    <React.Fragment>
      <h3 align="center">Add new transaction</h3>
      <Grid container className={classes.grid}>
        <form
          className={classes.root}
          noValidate
          autoComplete="off"
          onSubmit={onSubmit}
        >
          <MuiPickersUtilsProvider utils={DateFnsUtils}>
            <KeyboardDatePicker
              disableToolbar
              variant="inline"
              format="MM/dd/yyyy"
              margin="normal"
              id="Transaction Date"
              label="Transaction Date"
              onChange={e => setTransactionDate(e)}
              value={transactionDate}
              KeyboardButtonProps={{
                "aria-label": "change date"
              }}
            />
          </MuiPickersUtilsProvider>
          <TextField
            className={classes.textfield}
            id="Transaction Name"
            label="Transaction Name"
            variant="outlined"
            size="small"
            type="text"
            margin="dense"
            onChange={e => setText(e.target.value)}
            value={text}
            required = {true}
          />
          <TextField
            className={classes.textfield}
            id="Amount"
            label="Amount"
            variant="outlined"
            size="small"
            type="number"
            margin="dense"
            onChange={e => setAmount(e.target.value)}
            value={amount}
            required = {true}
          />
            <Button
              className={classes.button}
              variant="contained"
              color="primary"
              type="submit"
              fullwidth
            >
              Add transaction
            </Button>
        </form>
      </Grid>
    </React.Fragment>
  );
};

Глобальное состояние

import React, { createContext, useReducer } from 'react';
import AppReducer from './AppReducer';
import axios from 'axios';

// Initial state
const initialState = {
  transactions: [],
  error: null,
  loading: true
}

// Create context
export const GlobalContext = createContext(initialState);

// Provider component
export const GlobalProvider = ({ children }) => {
  const [state, dispatch] = useReducer(AppReducer, initialState);

  // Actions
  async function getTransactions() {
    try {
      const res = await axios.get('/api/v1/transactions');

      dispatch({
        type: 'GET_TRANSACTIONS',
        payload: res.data.data
      });
    } catch (err) {
      dispatch({
        type: 'TRANSACTION_ERROR',
        payload: err.response.data.error
      });
    }
  }

  async function deleteTransaction(id) {
    try {
      await axios.delete(`/api/v1/transactions/${id}`);

      dispatch({
        type: 'DELETE_TRANSACTION',
        payload: id
      });
    } catch (err) {
      dispatch({
        type: 'TRANSACTION_ERROR',
        payload: err.response.data.error
      });
    }
  }

  async function addTransaction(transaction) {
    const config = {
      headers: {
        'Content-Type': 'application/json'
      }
    }

    try {
      const res = await axios.post('/api/v1/transactions', transaction, config);
      dispatch({
        type: 'ADD_TRANSACTION',
        payload: res.data.data
      });
    } catch (err) {
      dispatch({
        type: 'TRANSACTION_ERROR',
        payload: err.response.data.error
      });
    }
  }

  return (<GlobalContext.Provider value={{
    transactions: state.transactions,
    error: state.error,
    loading: state.loading,
    getTransactions,
    deleteTransaction,
    addTransaction
  }}>
    {children}
  </GlobalContext.Provider>);
}

Редуктор приложения

export default (state, action) => {
  switch(action.type) {
    case 'GET_TRANSACTIONS':
      return {
        ...state,
        loading: false,
        transactions: action.payload
      }
    case 'DELETE_TRANSACTION':
      return {
        ...state,
        transactions: state.transactions.filter(transaction => transaction._id !== action.payload)
      }
    case 'ADD_TRANSACTION':
      return {
        ...state,
        transactions: [...state.transactions, action.payload],
      }
    case 'TRANSACTION_ERROR':
      return {
        ...state,
        error: action.payload
      }
    default:
      return state;
  }
}

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Я наконец смог решить это с помощью моего брата. Он предположил, что не было идеальным управлять частным состоянием формы отдельно от моего глобального состояния, но это сделало свою работу. Я сбрасываю состояние формы после вызова addTransaction.

Компонент формы

//No changes to import or styling //

export const AddTransaction = () => {
  const classes = useStyles();

  const [transactionDate, setTransactionDate] = useState(new Date());
  const [text, setText] = useState('');
  const [amount, setAmount] = useState(0);

  const { addTransaction } = useContext(GlobalContext);


  const onSubmit = e => {
    e.preventDefault();

    const newTransaction = {
      transactionDate,
      text,
      amount: +amount
    };

    addTransaction(newTransaction);

    // Here is what I've added that will return the form to it's original state

    setText('') //this resets the textfield to an empty string
    setAmount(0) //same as above but 0 amount

  };

//no changes to return//
0 голосов
/ 24 марта 2020

Здравствуйте, и спасибо за вопрос.

я бы решил эту проблему, используя хук usestate для поля ввода, а затем установив его на ноль с помощью onCLick. Вот пример:

предположим, у меня есть поле ввода с именем search на моем веб-сайте, которое связано с поиском Google. Это означает, что панель поиска на моем веб-сайте вызывает панель поиска на google. После того, как пользователь введет значение и нажмет на поиск, я вызову setSearch () для нового значения, которое вводится пользователем.

const [search, setSearch] = useState(""); // for user input

//once the user inputs a value and clicks a button I will call **two functions** 

//The first fires off a google search
const searchRequest = () => {
    window.open(`https://www.google.com/search?q=${search}`, `_blank`);
  };

// the second function does what you want, it sets the value of search to an empty string.

<Button variant="outlined" size="large" 
onClick={(e) => {
searchRequest(e);
setSearch(" ")}} // <-- I think this solves your problem, if you follow my logic.
>
  Search
 </Button>

Надеюсь, что это поможет, дайте мне знать, если мне нужно сделать это более ясным.

...