React - Очистить форму после отправки с помощью управления состоянием Context API
У меня есть простой трекер расходов с формой для добавления транзакций в серверную часть mongoDB. Я использую контекстный API и субкомпоненты формы UI материала. Я не могу понять, как очистить текстовые поля после запуска onSubmit, но я новичок в React и Javascript в целом. Я видел несколько других сообщений о создании функции, запускаемой как onClick с помощью кнопки, но я не уверен, что это правильный путь, поскольку у меня есть "initialState" в моем глобальном контексте. Я также видел другие маршруты, в которых для этого использовался appReducer, но я не мог понять, как это применить. Чтобы было ясно, я хочу, чтобы это очищало форму при отправке, а не кнопку для нажатия кнопки "очистить поля". Ниже мой код:
Компонент формы
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 ответа
Я, наконец, смог решить эту проблему с помощью моего брата. Он предположил, что было не идеально управлять частным состоянием формы отдельно от моего глобального состояния, но это сделало свою работу. Я сбрасываю состояние формы после вызова 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//
Привет и спасибо, что задали вопрос.
я бы решил эту проблему, используя хук usestate для поля ввода, а затем установив его на ноль с помощью onCLick. Вот пример:
Предположим, у меня есть поле ввода, называемое поиском на моем веб-сайте, которое связано с поиском 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>
Надеюсь, это поможет, дайте мне знать, если мне нужно пояснить.