目前我的表单中有一个问题,提交表单后我无法清除输入.. 我有两个用于输入和表单的文件:
form-hook.js
import { useCallback, useReducer } from 'react';
const formReducer = (state, action) => {
switch (action.type) {
case 'INPUT_CHANGE':
let formIsValid = true;
for (const inputId in state.inputs) {
if (!state.inputs[inputId]) {
continue;
}
if (inputId === action.inputId) {
formIsValid = formIsValid && action.isValid;
} else {
formIsValid = formIsValid && state.inputs[inputId].isValid;
}
}
return {
...state,
inputs: {
...state.inputs,
[action.inputId]: { value: action.value, isValid: action.isValid }
},
isValid: formIsValid
};
case 'SET_DATA':
return {
inputs: action.inputs,
isValid: action.formIsValid
};
default:
return state;
}
};
export const useForm = (initialInputs, initialFormValidity) => {
const [formState, dispatch] = useReducer(formReducer, {
inputs: initialInputs,
isValid: initialFormValidity
});
const inputHandler = useCallback((id, value, isValid) => {
dispatch({
type: 'INPUT_CHANGE',
value: value,
isValid: isValid,
inputId: id
});
}, []);
const setFormData = useCallback((inputData, formValidity) => {
dispatch({
type: 'SET_DATA',
inputs: inputData,
formIsValid: formValidity
});
}, []);
return [formState, inputHandler, setFormData];
};
这里我得到了一个 Input.js 文件:
import React, { useReducer, useEffect } from 'react';
import { validate } from '../../util/validators';
const inputReducer = (state, action) => {
switch (action.type) {
case 'CHANGE':
return {
...state,
value: action.val,
isValid: validate(action.val, action.validators)
};
case 'TOUCH': {
return {
...state,
isTouched: true
};
}
default:
return state;
}
};
const Input = props => {
const [inputState, dispatch] = useReducer(inputReducer, {
value: props.initialValue || '',
isTouched: false,
isValid: props.initialValid || false
});
const { id, onInput, clearInputs } = props;
const { value, isValid } = inputState;
useEffect(() => {
onInput(id, value, isValid);
}, [id, value, isValid, onInput]);
const changeHandler = event => {
dispatch({
type: 'CHANGE',
val: event.target.value,
validators: props.validators
});
};
const touchHandler = () => {
dispatch({
type: 'TOUCH'
});
};
const element =
props.element === 'input' ? (
<input
id={props.id}
type={props.type}
placeholder={props.placeholder}
onChange={changeHandler}
onBlur={touchHandler}
value={inputState.value}
maxLength={props.maxlength}
/>
) : (
<textarea
id={props.id}
rows={props.rows || 3}
onChange={changeHandler}
onBlur={touchHandler}
value={inputState.value}
/>
);
return (
<div
className={`form-control ${!inputState.isValid &&
inputState.isTouched &&
'form-control--invalid'}`}
>
<label htmlFor={props.id}>{props.label}</label>
{element}
{!inputState.isValid && inputState.isTouched && <p>{props.errorText}</p>}
</div>
);
};
export default Input;
我的问题是我无法访问这个 inputState,看起来值存储在其中... 这只是一个例子,如何在我的组件中使用它,这是 reactjs 中的函数式编程..
import React, { useState, useContext } from 'react';
import { Text, LanguageContext } from '../../lang/containers/Language';
import Input from '../../shared/components/FormElements/Input';
import Button from '../../shared/components/FormElements/Button';
import ErrorModal from '../../shared/components/UIElements/ErrorModal';
import {
VALIDATOR_EMAIL
} from '../../shared/util/validators';
import { useForm } from '../../shared/hooks/form-hook';
import { useHttpClient } from '../../shared/hooks/http-hook';
const NewSletter = () => {
const { dictionary } = useContext(LanguageContext);
const { isLoading, error, sendRequest, clearError } = useHttpClient();
const [joined, setJoined] = useState(false);
const [formState, inputHandler] = useForm(
{
email: {
value: '',
isValid: false
}
},
false
);
const newsletterSubmit = async event => {
event.preventDefault();
try {
const responseData = await sendRequest(
'http://localhost:5000/api/users/newsletter',
'POST',
JSON.stringify({
email: formState.inputs.email.value,
}),
{
'Content-Type': 'application/json'
}
);
if(responseData.message == 'subscribed'){
setJoined(true);
//here i need to clean all inputs in this form
}
} catch (err) {
console.log(err)
}
};
return (
<>
<ErrorModal error={error ? <Text tid={error}/> : null} onClear={clearError} />
<div className="newsletter-bg">
<div className="container">
<div className="newsletter-bg-title"><Text tid="newsletter"/></div>
<div className="space10px"></div>
<form className="newsletter-form" onSubmit={newsletterSubmit}>
<Input
element="input"
id="email"
type="email"
label={<Text tid="auth_lang4" />}
validators={[VALIDATOR_EMAIL()]}
errorText={<Text tid="auth_lang5" />}
onInput={inputHandler}
/>
<Button type="submit" disabled={!formState.isValid}>
<Text tid="add"/>
</Button>
{joined === true ? <div className="biltenmsg"> <span style={{color: 'green'}}><Text tid="joinedsletter"/></span> </div> : null}
</form>
</div>
</div>
</>
);
};
export default NewSletter;
我还尝试了这里的几个示例,如 reset() 和其他东西,也尝试更改 useForm 的内容,但我无法删除值,因为它从 inputState 中的 input.js 文件中读取值,我怎么想...我也尝试过setformdata 和其他一些示例,但我没有解决这个问题.. 最好的问候。
答案 0 :(得分:1)
只能通过 dispatch 更新 inputState
const inputReducer = (state, action) => {
switch (action.type) {
case 'CHANGE':
return {
...state,
value: action.val,
isValid: validate(action.val, action.validators)
};
case 'TOUCH': {
return {
...state,
isTouched: true
};
}
case 'RESET': {
return {
value: action.value,
isTouched: action.isTouched,
isValid: action.isValid
};
}
default:
return state;
}
};
然后
dispatch({
type: 'RESET',
value: props.initialValue || '',
isTouched: false,
isValid: props.initialValid || false
});
答案 1 :(得分:0)
我在您的 formReducer
中没有看到太多问题,它被 useForm
使用,并且您在内部定义了一个 inputHandler
,它是获得任何 input
工作所必需的.但是,恕我直言,您的 Input
过于复杂。
附上一个例子useForm
const useForm = (props = {}) => {
const [state, dispatch] = useReducer(reducer, initialState(props))
const change = useCallback((payload) => {
dispatch({ type: 'change', payload })
}, [])
const validate = useCallback((payload) => {
if (!state.validate) return
dispatch({ type: 'validate', payload: payload || state.values })
}, [state])
const submit = useCallback((payload) => {
dispatch({ type: 'submit', payload })
}, [])
const onChange = useCallback(e => {
const target = e.target
const payload = { [target.name]: target.value }
change(payload)
validate(payload)
}, [change, validate])
const onSubmit = useCallback(e => {
if (e) e.preventDefault()
submit(state.values)
}, [submit, state.values])
/**
* @typedef {object} useFormObject
* @property {string} name Form name
* @property {object} values Form values
* @property {func} change Form change function
* @property {object} handlers Form events
* @property {func} handlers.onChange Event upon input change
* @property {func} handlers.onSubmit Event upon form submit
* @property {func} validate Form validate function
* @property {object} errors Form errors
* @property {bool} error Form in error
*/
return {
name: state.name,
values: state.values,
change,
handlers: {
onChange,
onSubmit
},
validate,
errors: state.errors,
error: hasError(state.errors),
}
}
export default useForm
用法是
const { values, handlers, errors } = useForm({ initialValues })
然后每个输入小部件都是关于
<input value={values.abc} onChange={handlers.onChange} />
您可以看到在 reducer
中不需要另一个级别的 input
,因为 value
和 onChange
几乎都是从输入点开始的“只读”属性查看。
为完整起见,此处附上 reducer
。
import hasError from './hasError'
const defaultState = {
values: {},
errors: {},
watchers: {}
}
const reducer = (state = defaultState, action) => {
let payload = {}
if (action && action.payload) {
payload = action.payload
}
const watchers = state.watchers || {}
const watch = state.watch || (() => { })
const validate = state.validate || (() => { })
const { onSubmitted } = watchers
let errors
switch (action.type) {
case 'change':
watch(action.type, payload)
return {
...state,
values: {
...state.values,
...payload
}
}
case 'validate':
errors = validate(payload, action.type)
watch(action.type, errors)
return {
...state,
errors: {
...state.errors,
...errors
}
}
case 'submit':
errors = validate(payload, action.type)
watch('validation', errors)
if (hasError(errors)) {
return {
...state,
errors
}
}
if (onSubmitted) {
onSubmitted(state.values)
}
return state
default:
return state
}
}
export default reducer