React-使用Context API状态管理提交后清除表单

时间:2020-03-23 22:23:45

标签: reactjs forms material-ui react-state-management context-api

我有一个简单的Expense Tracker,它带有一个将事务添加到mongoDB后端的表单。我正在使用上下文API和材料UI表单子组件。我一辈子都无法弄清楚如何在onSubmit被触发后清除文本字段,但是总体来说我对React和Javascript还是很陌生。我还看过其他一些有关创建函数以使用按钮触发onClick的文章,但是由于我的全局上下文中有一个“ initialState”,因此我不确定这是正确的方法。我还看到了其他使用appReducer进行此操作的路线,但我不知道如何应用它。为了清楚起见,我希望它清除onSubmit表单,而不是单击“清除字段”的按钮。下面是我的代码:

表单组件

type    name    value    TTL
CNAME   www     @        1 hour

全球状态

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>
  );
};

App Reducer

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>);
}

2 个答案:

答案 0 :(得分:1)

我终于能够在哥哥的帮助下解决这个问题。他建议将表单的私有状态与我的全球状态分开管理是不理想的,但这已经完成了工作。我在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//

答案 1 :(得分:0)

您好,谢谢您提出问题。

我要解决此问题的方法是对输入字段使用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>

希望这会有所帮助,如果需要进一步说明,请告诉我。