I using library react-redux-toastr for our project. This library works great, except this case: codesandbox:
import React from "react";
import { useCallback } from "react";
import debounce from "lodash/debounce";
import { toastr } from "react-redux-toastr";
export default function Input({ value, onChange }) {
const toast = useCallback(
debounce(() => {
toastr.error("Interupt your typing", "Sorry, I blur your text input");
}, 500)
);
const setValue = e => {
onChange(e.target.value);
toast();
};
return (
<input
style={{ width: 500 }}
type="text"
value={value}
onChange={setValue}
/>
);
}
Basically, we want to let user keep typing in, and debouncedly call some API to update the input to database. Everything an API call is successful, show the toast. However, whenever the toast is displayed, the text input is unfocused.
in the CodeSandbox demo, you can try to type in anything, and see what the problem is.
Thanks.
Related
I am having multiple tab, each tabs load different components. In each components I have different set of forms. So there is a generic footer where user can click on save or continue.
So I am trying to use the react hook form useContext, but I am not getting the values.
I have reproduced the same issue on the below code.
SaveAndContinue component
import React from "react";
import { useFormContext } from "react-hook-form";
const Footer = (props) => {
const { formState, handleSubmit } = useFormContext();
const onSaveDetails = (data) => {
console.log("onSaveDetails", data);
};
const onContinue = (data) => {
console.log("onContinue", data);
};
return (
<>
<button
disabled={!formState?.isDirty}
onClick={handleSubmit(onSaveDetails)}
>
Save
</button>
<button disabled={!formState?.isDirty} onClick={handleSubmit(onContinue)}>
Continue
</button>
</>
);
};
export default Footer;
How can I get the formData of each component form when clicking on the save or continue button using react hook form context
Any help is appreciated
Here is the codesandbox
I looked at your codesandbox. the problem is:
on your ServiceDetails and UserDetails components you should register your inputs using useFormContext not useForm:
const { register } = useFormContext({
mode: "onBlur",
reValidateMode: "onChange",
defaultValues: {
firstName: ""
}
});
I tried to use onKeyPress, but since android doesnt get hard keyboard input, i want to use onSubmitEditing,
I have two TextInputs, what I want to do is that when I press on Enter when i am in textInput for firstName, it should be focused on next textInput
const firstNameRef = useRef(null);
const lastNameRef = useRef(null);
useEffect(()=> {
firstNameRef.current.focus();
}, [])
const firstKeyPress = (e) => {
if(e.key ==="Enter"){
lastNameRef.current.focus();
}
}
input.js
import React from "react";
import { TextInput, View } from "react-native";
const Input = React.forwardRef(({placeholder,onKeyPress},ref) => {
return(
<View>
<TextInput ref={ref} placeholder={placeholder}/>
</View>
)
})
export default Input;
Will I only add blurOnSubmit={false} onSubmitEditing={()=>lastNameRef.current.focus()} on Input component?
Yes, it worked.
I only added blurOnSubmit={false} onSubmitEditing={()=>lastNameRef.current.focus()} for the first TextInput, and called it as props, in input.js as blurOnSubmit={blurOnSubmit} onSubmitEditing={onsubmitEditing}
When i press on Enter while in first TextInput, it goes to other input.
I use reactjs. But when I handle onClick event. After I clicked on Button and dispatch an event. It's clear all my data in Input. I don't know why the data is cleared and how can prevent it.
import React, { useEffect } from "react";
import { Input, Form, Checkbox, Button, Row, Col, notification } from "antd";
import { loginRequest } from "../../../store/userStore";
import { useDispatch, useSelector } from "react-redux";
export default function SignInPage() {
const dispatch = useDispatch()
const handleSubmit = (e) => {
dispatch(loginRequest());
}
return (
<>
<Input>
</Input>
<Input>
</Input>
<Button onClick={() => {
handleSubmit()
}}>Click</Button>
</>
)
}
Issue
I'm guessing these inputs and button are being rendered with a form element and you aren't preventing the default form action from occurring. Button elements have a type="submit" by default, so when clicked will invoke the default form action and reload the page (clearing the inputs).
Solution
Call preventDefault on the event object.
const handleSubmit = (e) => {
e.preventDefault(); // <-- prevent the default
dispatch(loginRequest());
}
I created a custom input called <FormInput> and applied useField() and useFormikContext() to it:
const [field, meta] = useField(props);
const { setFieldValue } = useFormikContext();
<FormInput> is part of a library called UI. I'm importing the library and trying to create a very simple form to test, a single field, the only validation being that it's required:
import React, { useContext } from "react";
import { DataContext } from "../../context/DataContext";
import * as UI from "#tui/uilibrary";
import { composeThemeFromProps } from "#css-modules-theme/react";
import styles from "./EnrollStep5.module.scss";
import { Formik, Form } from "formik";
import * as Yup from "yup";
const EnrollStep5 = (props) => {
const context = useContext(DataContext);
const theme = composeThemeFromProps(styles, [context, props]);
return (
<Formik
initialValues={{
name: "",
}}
validationSchema={Yup.object().shape({
name: Yup.string().required("Required"),
})}
>
{(props) => {
<Form className={theme.EnrollStep2}>
<UI.FormInput type={"text"} name={"name"} label={"Name"} />
</Form>;
}}
</Formik>
);
};
export default EnrollStep5;
This comes up blank. The Formik object appears in the Component browser, but shows as if it has no children. I have the feeling this is just due to inexperience and that I'm close. What am I doing wrong?
In short:
Wrap the <Form>...</Form> in (parantheses) instead of {curly braces}.
Little more detailed:
So basically what is happening in your code with the curly braces is you are entering the callback function. So the <Form>...</Form> is just floating around somewhere in the function body. What you intend to do is to return it.
So you can either add a return statement (return <Form>...</Form>;) inside the curly braces or directly return the value without entering the function body. E.g. like (props) => <Form>...</Form> or (props) => (<Form>...</Form>), whichever you prefer.
I have an antd form where I am able to get the form data in onFinish function upon hitting submit button in which I wanted to use uesEffect hook and dispatch an action with form data as payload to redux saga but I got following error
React Hook "useEffect" is called in function "onFinish" that is neither a React function component nor a custom React Hook function.
If I write useEffect hook outside the onFinsh function, I am unable to get the form data/values
Please suggest a workaround to get the form data values outside of onFinish function
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Form, Input, Button, Checkbox } from 'antd';
const Demo = () => {
const onFinish = (values) => {
// alert(JSON.stringify(values['username']));
useEffect(() => {
// dispatch an action with values as payload
}, []);
};
console.log(values) // UNABLE TO GET VALUES HERE...HOW TO GET IT???
return (
<Form
name="basic"
onFinish={onFinish}>
<Form.Item
label="Username"
name="username">
<Input />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
It looks like you don't even need the useEffect() hook. Just dispatch the action from within the onFinish() and have state store the values
const Demo = () => {
const [ values, setValues ] = useState([]);
const onFinish = (recievedValues) => {
// dispatch here
setValues(recievedValues);
}
console.log(values) // <-- you can get it here
return (<div> ... </div>);
};
Or better yet, since you are already saving the values in redux during dispatch, you should use that in your render code as well:
import { useSelector } from 'react-redux';
const Demo = () => {
//point to the state where your data is
const stateValues = useSelector(state => state.your.data);
const onFinish = (recievedValues) => {
// dispatch here
}
console.log(stateValues) // <-- you can get it here
return (<div> ... </div>);
};
useEffect can only be called at the top level of your component, not within a function. In this case, you shouldn't need useEffect to dispatch the action, and instead can just do so directly inside onFinish.