Why query not updated value but get initial value in Function with ExtReact - extreact

I have form fn
code here
#update code. I initialization
query = {
field: '',
email: '',
}
not initialization url
export function HomePage() {
const [query, setQuery] = useState({
field: '',
email: '',
});
const handleChaneValue = (value) => {
// not received data on change
console.log('query', query);
setQuery({
...query,
[value.sender.name]: value.newValue
})
}
console.log('query2', query);
query2 received data on change
console.log('query2', query);
#Update code: I add
return (
<div>
<Container
padding={10}
platformConfig={{
desktop: {
maxWidth: 400,
}
}}
>
<FormPanel
padding={10}
shadow
defaults={{
errorTarget: 'under'
}}
margin="0 0 20 0"
title="Using Validators"
>
<Textfield
required
label="Required Field"
requiredMessage="This field is required."
errorTarget="under"
name="field"
onChange={handleChaneValue}
/>
<EmailField
label="Email"
validators="email"
errorTarget="under"
name="email"
onChange={(e) => handleChaneValue(e)}
/>
<Urlfield
label="URL"
validators={{
type: 'url',
message: 'Website url example http://'
}}
errorTarget="under"
name="url"
onChange={handleChaneValue}
/>
<Container layout="center">
<Button
ui="confirm"
text="BTN submit"
handler={handleClick}
style={{border: '1px solid black' }}/>
</Container>
</FormPanel>
</Container>
</div>
)
}
export default HomePage;
When I change value in TextField. Query is
query2: {field: 'abc'}
But i change value in Email field. Query is not give old value "{filed: 'abc'}" throught I use ES6 three dot.
query2 : {email: 'xyz'}
and Query in funciton always initialization
query: {}
image change value
#Update image: when I change value Url. fn handleChangeValue get initialization query
query: {
field: '',
email: '',
}
does not value query updated.

here issues were you did not initialize the value of textfield and emailfield I updated code pls check now
export function HomePage() {
const [query, setQuery] = useState({
field:'',
email:''
});
const handleChaneValue = (value) => {
// not received data on change
console.log("query", query);
setQuery({
...query,
[value.sender.name]: value.newValue,
});
};
console.log("query2", query);
return (
<div>
<Container
padding={10}
platformConfig={{
desktop: {
maxWidth: 400,
},
}}
>
<FormPanel
padding={10}
shadow
defaults={{
errorTarget: "under",
}}
margin="0 0 20 0"
title="Using Validators"
>
<Textfield
required
label="Required Field"
requiredMessage="This field is required."
errorTarget="under"
name="field"
onChange={handleChaneValue}
value={query.field}
/>
<EmailField
label="Email"
validators="email"
errorTarget="under"
name="email"
value={query.email}
onChange={handleChaneValue}
/>
<Container layout="center">
<Button
ui="confirm"
text="BTN submit"
handler={handleClick}
style={{ border: "1px solid black" }}
/>
</Container>
</FormPanel>
</Container>
</div>
);
}
export default HomePage;

I found the solution to the problem. I using framework ExtReact so when run function, states re-initialized initil value. To solve this problem you can useRef and refer here.
enter link description here

Related

Material UI TextField select not showing initial value on form edit

I have an edit form in a modal that lets you edit user info. Here is the relevant portion:
export const EditUserModal = (Props) => {
const [formValues, setFormValues] = useState(Props.userData);
const [reporterData, setReporterData] = React.useState<any[]>([]);
React.useEffect(() => {
let apiClient = new APIClient();
apiClient.getOwners().then((response) => {
setReporterData(response);
});
}, []);
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormValues({
...formValues,
[name]: value,
});
};
return (
<>
<Modal
open={Props.show}
onClose={() => { Props.toggleModal(false)}}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box
component="form"
autoComplete="off"
>
<Typography id="modal-modal-title" variant="h4" component="h4">
Edit User {Props.userData.name}
</Typography>
<div>
<TextField
required
id="outlined-select-basic"
select
name="reports_to"
label="Reports To"
value={formValues.reports_to}
onChange={handleInputChange}
>
{reporterData.map((option) => (
<MenuItem key={option.owner} value={option.owner}>
{option.owner}
</MenuItem>
))}
</TextField>
</div>
</Box>
</Modal>
</>
)
};
The TextField is supposed to show the initial value of {formValues.reports_to}, but it remains blank (the value is still correct) until you make a new selection. reporterData just returns a list of names(string).
I have tried adding it as a defaultValue, which did not work.

File upload using formik and express backend

I am trying to upload an image along with a title and some text for a post. I am using Formik form with an onSubmit in the client folder of the project :
const [charCount, setCharCount] = useState(0);
const [fileObject, setFileObject] = useState(null);
const initialValues = {
title: "",
postText: "",
file: null
};
const validationSchema = Yup.object({
title: Yup.string().required("Required"),
postText: Yup.string().required("Required"),
});
const onSubmitHandler = (values) => {
const formData = new FormData();
formData.append("title", values.title);
formData.append("postText", values.postText);
console.log(fileObject);
formData.append("file", document.getElementById("file").files[0]);
console.log(formData);
axios
.post(
"http://localhost:3001/posts/create",
formData,
{
headers: {
accessToken: localStorage.getItem("token"),
},
}
)
.then((response) => {
console.log(response.data);
});
};
return (
<>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmitHandler}
>
<Form className="create-post-form">
<input type="file" name="file" id="file" onChange={(e) => {
setFileObject(e.target.files[0]);
}}/>
<Field id="input-create-post" name="title" placeholder="Post Title" />
<ErrorMessage name="title" component="span" className="error" />
<Field
id="input-create-post-text"
name="postText"
placeholder="What's the story?"
as="textarea"
onKeyUp={(e) => setCharCount(e.target.value.length)}
maxLength="250"
/>
<div className="char-count">
<span id={charCount===250 ? "char-count-max" : "char-count"}>{charCount}/250</span>
</div>
<ErrorMessage name="title" component="span" className="error" />
<Button type="submit" title="Post" onSubmit={onSubmitHandler} />
</Form>
</Formik>
</>
);
};
On the server side (server folder), in the Posts.js route where I am handling the request :
router.post("/create",validateToken, async(req,res)=>{
if(req.files === null){
return res.status(400).json({message: "No file uploaded"});
}
const file = req.files;
console.log(file);
res.json(req.body)
})
On submitting the form, an empty object {} is logged on the console. And the res.json(req.body) returns the title and postText successfully, but the file is {} (empty). How do I fix this? Please help!
I tried submitting the form with the above code and got this response:
result image
I need the file object to be the actual fileObject that I have as a state.

Reference problem with external UI library in React Hook Form

I'm using the ReactSelect component, however, I created a component called Select and ReactSelect is in there:
interface IProps extends ISelectProps {
tabIndex: string;
required: boolean;
isClearable: boolean;
isDisabled: boolean;
placeholder: string;
options: {
label: string;
value: string;
}[];
}
const Select = ({ ...props }: IProps) => <ReactSelect {...props} />;
export default Select
;
The error is as follows:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `Controller`.
at Select
Here's the code:
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete='off'>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
{API.map(({ id, order, htmlControl }) => (
<Controller
key={id}
name={id}
control={control}
render={({ field, fieldState: { error } }) => (
<>
{htmlControl.type === 'PARAMETER_TYPE_SELECT' && (
<Select
{...field}
isClearable={true}
error={!!error}
tabIndex={order.toString()}
required={htmlControl.isRequired}
isDisabled={htmlControl.isDisabled}
placeholder={htmlControl.placeholder}
options={htmlControl.options}
/>
)}
{htmlControl.type !== 'PARAMETER_TYPE_SELECT' && (
<input
required={htmlControl.isRequired}
disabled={htmlControl.isDisabled}
placeholder={htmlControl.placeholder}
/>
)}
</>
)}
/>
))}
</div>
<input type='submit' />
</form>
I'm following exactly like the official documentation and I can't understand why it can't get the reference.
As you read the warning, it says you are attempting to assign ref attribute to a functional component which is not correct, you should not use the ref attribute on function components because they don’t have instances. To solve your problem you can define your Select component by using React.forwardRef like this:
const Select = React.forwardRef(({ ...props }, ref) => (
<ReactSelect {...props} ref={ref} />
));

Resetting a formik form in react-native on navigation

I am trying to create a React Native app that can create and edit entities.
For example, users.
I have a formik form that takes first and last name, as well as an email address.
If a user params is passed, then the form should take on those values.
However, it only works the first time. After that, the form keeps the first values.
How can I force the form to be reevaluated?
function FormScreen({ navigation, route }) {
const formikRef = React.createRef();
const initialValues = { firstName: "", lastName: "", email: "" };
if (route.params && route.params.user) {
if (route.params.user.firstName) {
initialValues.firstName = route.params.user.firstName;
}
if (route.params.user.lastName) {
initialValues.lastName = route.params.user.lastName;
}
if (route.params.user.email) {
initialValues.email = route.params.user.email;
}
}
const unsubscribeBlur = navigation.addListener("blur", (e) => {
console.log("form blur");
if (formikRef.current) {
console.log("form reset");
formikRef.current?.resetForm();
}
});
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Formik
innerRef={formikRef}
initialValues={initialValues}
validationSchema={Yup.object({
firstName: Yup.string()
.max(15, "Must be 15 characters or less")
.required("Required"),
lastName: Yup.string()
.max(20, "Must be 20 characters or less")
.required("Required"),
email: Yup.string()
.email("Invalid email address")
.required("Required"),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
<Form>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" type="text" />
<ErrorMessage name="firstName" />
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" type="text" />
<ErrorMessage name="lastName" />
<label htmlFor="email">Email Address</label>
<Field name="email" type="email" />
<ErrorMessage name="email" />
<button type="submit">Submit</button>
</Form>
</Formik>
</View>
);
}
export default FormScreen;
I have code in there to reset the form on blur but the reset doesn't seem to do anything.
You can find the complete code in a snack.
https://snack.expo.io/#hackzilla/create-and-edit-with-formik
Because you are using a tab navigator. The home and form screen will not reMount when you toggle between them.So the formik will not load the new initialValues.In your way,you can reset the form using route params everytime the form screen is focused.But a better way is using a stack navigator,every time create a form using a new instance.
useFocusEffect(
React.useCallback(() => {
if (formikRef.current) {
console.log("form reset");
formikRef.current?.setValues(initialValues);
}
})
);
We can reset the form after submit, so that it will clear all the fields. Please try by replacing your submit method with below mentioned code.
onSubmit={(values, { setSubmitting, resetForm }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
// reset the fields after submit
resetForm();
}, 400);
}}

Editing a Material UI row within React + Redux

I have a material UI table in a react project, and I want a user to click on the pencil/Edit Icon to edit the table row.
This is a loaded question, but would this require an additional piece of Material UI? what would the logic look like to make this happen?? I have most of the code set up on the backend, but don't know how to write this code in the component???
Thanks for looking!
//STYLE VARIABLE BOR MATERIAL BUTTON
const style = {
margin: 12
//
};
const mapStateToProps = (state) => ({
user: state.user,
reduxState: state.getExpense
});
class ExpenseTable extends Component {
constructor(props) {
super(props);
this.state = {
getExpense: []
};
}
isSelected = (index) => {
return this.state.selected.indexOf(index) !== -1;
};
handleRowSelection = (selectedRows) => {
this.setState({
selected: selectedRows,
});
};
//on page load, DISPATCH GET_EXPENSE is
//SENT TO expenseSaga which then
//goes to getExpenseReducer and appends EXPENSE_DATA to the
//DOM
componentDidMount() {
const { id } = this.props.match.params;
this.props.dispatch({ type: USER_ACTIONS.FETCH_USER });
this.props.dispatch({ type: 'GET_EXPENSE' });
}
componentDidUpdate() {
if (!this.props.user.isLoading && this.props.user.userName ===
null) {
this.props.history.push('home');
}
}
logout = () => {
this.props.dispatch(triggerLogout());
// this.props.history.push('home');
};
//SETS STATE FOR ALL INPUTS
handleChange = (name) => {
return (event) => {
this.setState({
[name]: event.target.value
});
};
};
//SUBMIT BUTTON- TRIGGERS DISPATCH TO EXPENSE SAGA TO ADD DATA
handleClick = () => {
console.log('add expense', this.state);
this.props.dispatch({
type: 'ADD_EXPENSE',
payload: this.state
});
};
//TRASH ICON-TRIGGERS DISPATCH TO EXPENSE SAGA DELETE
handleClickRemove = (id) => {
console.log('delete expense', this.state);
this.props.dispatch({
type: 'DELETE_EXPENSE',
payload: id
});
};
handleClickEdit = (row) => {
console.log('edit expense', this.state)
this.props.dispatch({
type: 'EDIT_EXPENSE',
payload: row
})
}
render() {
console.log('HEY-oooo expense render', this.state);
let content = null;
if (this.props.user.userName) {
//MAP OVER REDUX STATE.
const tableRows = this.props.reduxState.map((row) => {
//.MAP SEPARATES DATA INTO INDIVIDUAL ITEMS.
const { id, item_description, purchase_date,
item_price, item_link } = row;
return (
<TableRow selectable={false}>
{/* TABLE ROWS */}
<TableRowColumn>{item_description}
</TableRowColumn>
<TableRowColumn>{purchase_date}
</TableRowColumn>
<TableRowColumn>${item_price}</TableRowColumn>
<TableRowColumn><a href={item_link}>{item_link}
</a></TableRowColumn>
<TableRowColumn><EditIcon class="grow:hover"
onClick={() => {this.handleClickEdit(row)}} />
</TableRowColumn>
<TableRowColumn><TrashIcon onClick={() =>
{this.handleClickRemove(id);
}}/>
</TableRowColumn>
</TableRow>
// END TABLE ROWS
);
});
<div>
{/* FORM FOR ADDING EXPENSES(DATA) */}
<form id="expenseForm">
<h3>
Add a new <br />
expense
</h3>
<input
type="text"
id="fname"
name="fname"
placeholder="Item description"
onChange=
{this.handleChange('item_description')}
/>
<br />
<br />
<input
type="text"
id="lname"
name="lname"
placeholder="Item price"
onChange={this.handleChange('item_price')}
/>
<br />
<input
type="text"
id="lname"
name="lname"
placeholder="Item link"
onChange={this.handleChange('item_link')}
/>
<br />
{/* END FORM */}
<RaisedButton
id="expSubmit"
label="Submit Expense"
primary={true}
style={style}
onClick={this.handleClick}
/>
{/* TABLE TOTAL KEEPS CURRENT TOTAL OF PRICE COLOUMN */}
<h1>Total:</h1>
<br />
<h3>$748.93</h3>
</form>
{/* TABLE HEADERS */}
<Table>
<TableHeader>
<TableRow>
<TableHeaderColumn>Item
description</TableHeaderColumn>
<TableHeaderColumn>Purchase
Date</TableHeaderColumn>
<TableHeaderColumn>Item
Price</TableHeaderColumn>
<TableHeaderColumn>Item
Link</TableHeaderColumn>
<TableHeaderColumn>Edit
entry</TableHeaderColumn>
<TableHeaderColumn>Delete
entry</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody>
{tableRows}
</TableBody>
</Table>
</div>
);
}
return (
<div>
<Nav />
{content}
</div>
);
}
}
// this allows us to use <App /> in index.js
export default connect(mapStateToProps)(ExpenseTable);
The default material-ui table doesn't have the feature of in-line editing. You will have to write your own wrapper to achieve this which can be time consuming. To overcome the time issue we can use some good existing libraries.
Here's one powerful library from DevExtreme for the same which i used, but go through their licensing before you take the final decision to use.
https://devexpress.github.io/devextreme-reactive/react/grid/demos/featured/controlled-mode/