I'm building a React + PHP API app which let's visitors of the page subscribe to newsletter. I'm using Hooks, Axios and Typescript as well. I tested the API with Postman and the data gets submitted as it should. But when I do the post from frontend, the data comes over and gets inserted in the database twice - one normal row and an empty row.
My code for frontend
import React, { FormEvent } from 'react';
import { useForm } from "react-hook-form";
import axios from 'axios';
import { BsArrowRight } from 'react-icons/bs';
interface IFormNewsletter {
email: string;
emailProvider: string;
dateCreated: number;
}
const FormNewsletter: React.FC = () => {
const { register, handleSubmit } = useForm<IFormNewsletter>();
const preventDefault = (e: FormEvent) => {
e.preventDefault();
}
const onSubmit = (data: IFormNewsletter) => {
data.emailProvider = data.email.split('#')[1];
data.dateCreated = Math.round((new Date()).getTime() / 1000);
axios.post('http://localhost/mb-backend/api/create', {
email: data.email,
emailProvider: data.emailProvider,
dateCreated: data.dateCreated
})
.then((response) => {
console.log(response);
}, (error) => {
console.log(error);
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="input-box">
<input ref={register} className="newsletter" type="text" name="email" id="email" placeholder="Type your email address here…" />
<button type="submit" className="submit" name="submit" id="submit"><BsArrowRight className="submit-arrow" /></button>
</div>
<div className="tos-box">
<label className="check-container">
<input type="checkbox" />
<span className="checkmark"></span>
</label>
<span className="tos-label">I agree to terms of service</span>
</div>
</form>
)
}
export default FormNewsletter;
This is how the post gets inserted:
What I tried is to use the preventDefault method, but it stops the form from submitting at all:
<form onSubmit={(e) => {
e.preventDefault();
handleSubmit(onSubmit);
}}>
I also tried to use fetch instead of axios but the result is the same. I'm new to React and would appreciate the help.
EDIT:
The backend looks like this:
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Access-Control-Allow-Headers,Content-Type,Access-Control-Allow-Methods,Authorization,X-Requested-With');
include_once '../config/Database.php';
include_once '../models/User.php';
$database = new Database();
$db = $database->connect();
$user = new User($db);
$data = json_decode(file_get_contents("php://input"));
$user->dateCreated = $data->dateCreated;
$user->email = $data->email;
$user->emailProvider = $data->emailProvider;
if ($user->create()) {
echo json_encode(
array('message' => 'User created')
);
} else {
echo json_encode(
array('message' => 'Could not create user')
);
}
add disabled={formState.isSubmitting}>
<button type="submit" disabled={formState.isSubmitting}> className="submit" name="submit" id="submit"><BsArrowRight className="submit-arrow" /></button>
Related
I'm trying to add next-auth authentication with credentials(it's my first time and the source I'm using for following is using version 3 as I know, therefore there is a lot of difference and I couldn't find the right solution for days). Basically I have got form of registration and log-in form, and as a backend server I'm using mongodb. the registration form works normally, user is able to create account, but the log-in form doesn't seem to be working and in console when user sends request for logging in comes up error: {error: 'client.db.collection is not a function', status: 401, ok: false, url: null}.
This is pages/api/[...nextauth].js file.
import { verifyPassword } from "#/lib/auth";
import connectToDatabase from "#/lib/db";
import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";
export default NextAuth({
session: {
strategy: "jwt",
},
providers: [
CredentialsProvider({
async authorize(credentials, req) {
const client = await connectToDatabase();
const userCollection = client.db.collection("users");
const user = await userCollection.findOne({ email: credentials.email });
if (!user) {
client.close();
throw new Error("No user found!");
}
const isValid = verifyPassword(credentials.password, user.password);
if (!isValid) {
client.close();
throw new Error("Could not log you in.");
}
client.close();
return { email: user.email };
},
}),
],
});
and this is loginForm.js that should send request to log-in.
import React, { useRef } from "react";
import Link from "next/link";
import { signIn } from "next-auth/react";
const LoginForm = () => {
const emailRef = useRef();
const passwordRef = useRef();
const submitHandler = async (e) => {
e.preventDefault();
const enteredEmail = emailRef.current.value;
const enteredPassword = passwordRef.current.value;
try {
const result = await signIn("credentials", {
redirect: false,
email: enteredEmail,
password: enteredPassword,
});
console.log(result);
} catch (error) {
console.log(error.error);
}
};
return (
<div
className="container d-flex justify-content-center align-items-center"
style={{ width: "100%", height: "100vh" }}
>
<div className="col-6-sm">
<form onSubmit={submitHandler}>
<div className="form-outline mb-4">
<input
type="email"
id="form2Example1"
className="form-control"
ref={emailRef}
/>
<label className="form-label" for="form2Example1">
Email address
</label>
</div>
<div className="form-outline mb-4">
<input
type="password"
id="form2Example2"
className="form-control"
ref={passwordRef}
/>
<label className="form-label" for="form2Example2">
Password
</label>
</div>
<button type="submit" className="btn btn-dark m-1">
Sign in
</button>
<Link href="/register" className="btn btn-dark m-1">
Register
</Link>
</form>
</div>
</div>
);
};
export default LoginForm;
Got my Landing page in here with hardcoded username / password into firebase db.
after successful login, I am redirected to the homepage. However, I am trying to figure out how to fetch the data for the specific logged in user. Currently, in my Firebase I have only 1 Collection which is Users and contains some documents any of the documents has their own fields it is all hardcoded for the sake of the test.
After the log in I am currently logging data but I only see the last added document. How do i attach the User to see its own data. I tried creating directly in firebase a document with the same UID as the logging user but the data that i am logging is still the last added document instead of the right for the specific user.
function LandingPage(props) {
const [showErrorModal, setShow] = useState(false);
const emailInputRef = useRef();
const passwordInputRef = useRef();
const navigate = useNavigate();
function sumbitForm(e) {
e.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredPassword = passwordInputRef.current.value;
const url = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyCNBAxjeKNoAPPjBV0JW4vZ0QaTaOx9-L4';
fetch(url, {
method: 'POST',
body: JSON.stringify({
email: enteredEmail,
password: enteredPassword,
returnSecureToken: true,
}),
headers: {
'Content-Type': 'application/json',
},
}).then((res) => {
if (res.ok) {
navigate('/homepage')
} else {
setShow(true);
}
return res.json()
}).then((data) =>
console.log(data))
}
function handleClose() {
setShow(false)
}
return (
<div className='wrapper'>
<form onSubmit={sumbitForm}>
<h3>Login Here</h3>
<label htmlFor="username">Username</label>
<input type="text" placeholder="Sigh up with email" id="username" ref={emailInputRef} ></input>
<label htmlFor="password">Password</label>
<input type="password" placeholder="Password" id="password" ref={passwordInputRef}></input>
<button className='button' type="submit" typeof='submit' >Log In</button>
{showErrorModal ? <Modal show={showErrorModal} onHide={handleClose}
backdrop="static">
<Modal.Header>
<Modal.Title>Incorrect Username/Password</Modal.Title>
</Modal.Header>
<Modal.Body>
Please provide the correct credentials
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
</Modal.Footer>
</Modal> : null}
<div className='landingpage-logo'>
<img src={logo} className="landingpage-logo"></img>
</div>
</form>
</div>
)
}
export default LandingPage;
import React, { useEffect, useState } from "react";
import { getDatabase, ref, onValue } from "firebase/database";
import { db, firebase } from '../../firebase';
import 'firebase/compat/auth';
const HomeScreen = (props) => {
const [loadedData, setLoadedData] = useState([]);
const username = props.email.substring(0, props.email.indexOf('#'))
useEffect(() => {
readData();
}, [])
async function readData() {
db.collection('Users').get().then((querySnapshot) => {
querySnapshot.forEach(element => {
const incomingData = element.data();
setLoadedData(incomingData)
})
})
}
return (
<div className={styles['wrapper']}>
</div>
)
}
export default HomeScreen;
I created a simple project in react by using firebase to use crud proccessing.
https://github.com/celalaygar/web-push/tree/master/react-firebase-CRUD-example
in package.json->dependencies : "firebase": "^7.14.1"
in this file fetch data method is here.
https://github.com/celalaygar/web-push/blob/master/react-firebase-CRUD-example/src/components/main.component.js
fetchData = async () => {
const db = firebase.firestore();
const data = await db.collection("spell").get();
result = data.docs.map(doc => ({ ...doc.data(), id: doc.id }));
this.setState({ spell: result });
}
I'm creating a todo app and I'm thinking of sending the id of the todo I want to delete using the post method to delete it. I'm currently using <form action="localhost" method="delete">, but I'd like to do something a little more complicated, so I'm trying to pass the id to the OnSubmit handler. is there a way to use the id in OnSubmit? Is there any way to use id in OnSubmit?
Implemented code
import React, {useState, useEffect} from "react";
import axios from "axios";
interface Todo {
id: number,
text: string,
}
const ShowContent = () => {
const [todoes, setTodoes] = useState<Todo[]>([]);
useEffect(() => {
axios.get<Todo[]>("http://localhost:8888")
.then(res => {
setTodoes(res.data)
})
.catch(_ => alert("useeffect error"))
}, [])
return (
<div>
<h1>Todo App</h1>
{todoes.map(todo =>
<div key={todo.id}>
<div>id: {todo.id}, text: {todo.text}</div>
<form action="localhost:8888" method="post">
<input type="hidden" name="id" value={todo.id}></input>
<button>Delete</button>
</form>
</div>
)}
<div>
<form action="localhost:8888" method="post">
<input type="text"></input>
<button>Submit</button>
</form>
</div>
</div>
);
}
What I want to do
import React, {useState, useEffect} from "react";
import axios from "axios";
interface Todo {
id: number,
text: string,
}
const ShowContent = () => {
const [todoes, setTodoes] = useState<Todo[]>([]);
useEffect(() => {
axios.get<Todo[]>("http://localhost:8888")
.then(res => {
setTodoes(res.data)
})
.catch(_ => alert("useeffect error"))
}, [])
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// I want to get the id here.
}
return (
<div>
<h1>Todo App</h1>
{todoes.map(todo =>
<div key={todo.id}>
<div>id: {todo.id}, text: {todo.text}</div>
<form onSubmit={handleOnSubmit}>
<input type="hidden" name="id" value={todo.id}></input>
<button>submit</button>
</form>
</div>
)}
</div>
);
}
export default ShowContent;
It is possible to get the id from your hidden input through the event using e.target either with FormData or document.querySelector, but there are Typsecript issues with this.
You already have access to the todo in the loop where you create the form, so my recommendation is that you create a function which already knows the id.
You can change your handler to a curried function like this:
const handleOnSubmit = (id: number) => (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log(`submitted todo ${id}`);
}
And use it like this:
<form onSubmit={handleOnSubmit(todo.id)}>
So, i'm making this social network app and it has user profile. if user wants to update profile, eg. name, by opening modal EditUser, the old value of users name should be there, in input filed, and user needs to have opportunity to change/update that.
I used 'defaultValue', and there is it, in input field, but if i don't change anything in that field, just click 'update', it will be lost. updated value is empty string then, and not the value that is showing in that field. how can i fix this?
Also interested how to set as default user image. so, user has profile image, and on update if user changes only name, not the picture or something else, everything else should be the same, but photo is also like input text field lost.
here is what i tried:
MyProfile.tsx
import React, { useState, useEffect, useContext } from 'react'
import './myprofile.css'
import Axios from 'axios'
import SinglePost from '../single_post/SinglePost'
import { AppContext } from '../context/AppContext'
import UpdateProfile from '../modals/UpdateProfile'
function MyProfile() {
const [userInfo, setUserInfo] = useState({
firstName: '',
lastName: '',
userBio: 'Write something about yourself.',
userPhoto: ''
})
const [isEditOpen, setIsEditOpen] = useState(false)
const { userID, setUserID } = useContext(AppContext)
// open modal on click 'edit'
const editUser = () => {
setIsEditOpen(true)
}
// get user data
const storedToken = localStorage.getItem('token')
useEffect(() => {
const config = {
headers: { "x-auth-token": `${storedToken}` }
}
Axios
.get('/api/auth/user', config)
.then(res => {
console.log('response', res)
const user = res.data.user
setUserID(user._id)
setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}, [])
return (
<div className="profile-container">
<button className="btn-edit" onClick={editUser}>
<i className="fa fa-edit"></i>
</button>
<div className="user-info">
<div className="img-circular">
<img className="user-profile-img2" src={userInfo.userPhoto}></img>
</div>
<p className="user-name">{userInfo.firstName} {userInfo.lastName}</p>
<p className="about-user">{userInfo.userBio}</p>
</div>
<div className="user-posts">
<p className="my-posts-title">My Posts</p>
</div>
{isEditOpen && <UpdateProfile
userID={userID}
setIsEditOpen={setIsEditOpen}
isEditOpen={isEditOpen}
setUserInfo={setUserInfo}
userInfo={userInfo}
/>}
</div>
)
}
export default MyProfile
UpdateProfile.tsx
import React, { useState, useRef, useEffect } from 'react'
import { Modal, ModalHeader, ModalBody, ModalFooter, Button, FormGroup, Label, Input } from 'reactstrap'
import Axios from 'axios'
import '../user_profile/myprofile.css'
function UpdateProfile(props: any) {
const [firstNameUpdated, setFirstNameUpdated] = useState('')
const [lastNameUpdated, setLastNameUpdated] = useState('')
const [userBioUpdated, setUserBioUpdated] = useState('')
const inputNameRef = useRef<HTMLInputElement | any>(null)
useEffect(() => {
console.log(inputNameRef.current, props.userInfo.firstName)
inputNameRef.current && (inputNameRef.current.value = props.userInfo.firstName)
}, [])
// upload image
const [file, setFile] = useState('')
const [uploaded, setUploaded] = useState('')
const handleImageUpload = (e: any) => {
e.preventDefault();
setFile(e.target.files[0])
};
const onClickHandler = (e: any) => {
const formData = new FormData()
formData.append('fileImage', file)
Axios.post("/api/image", formData, {})
.then(res => {
//console.log(`UPLOADED: http://localhost:5000/${res.data.fileImage}`)
setUploaded(`http://localhost:5000/${res.data.fileImage}`)
})
.catch(err => console.log(err))
}
// update user
const updateUser = (e: any) => {
e.preventDefault()
props.setIsEditOpen(false)
const formData = new FormData()
formData.append('fileImage', file)
formData.append('first_name', firstNameUpdated)
formData.append('last_name', lastNameUpdated)
formData.append('user_bio', userBioUpdated)
const config: any = { header: { "Content-Type": "multipart/form-data" } }
Axios
.put(`/api/users/${props.userID}`, formData, config)
.then(res => {
const user = res.data
props.setUserInfo({
firstName: user.first_name,
lastName: user.last_name,
userBio: user.user_bio,
userPhoto: user.profile_image
})
})
.catch(err => console.log(err))
}
return (
<div>
{props.isEditOpen &&
<Modal isOpen={props.isEditOpen} toggle={() => props.setIsEditOpen(!props.isEditOpen)} backdrop="static">
<ModalHeader>Update your profile</ModalHeader>
<ModalBody>
<FormGroup>
<Label>Profile Image</Label>
<Input type="file" name="fileImage" onChange={handleImageUpload}></Input>
</FormGroup>
<Button onClick={onClickHandler} className="btn-upload-img">Upload file</Button>
<div className="inline">
{uploaded ? <img src={uploaded} style={{ width: "100px" }}></img> : <img src={props.userInfo.userPhoto} style={{ width: "100px" }}></img>}
</div>
<FormGroup>
<Label>First Name</Label>
<Input type="text" onChange={(e: any) => setFirstNameUpdated(e.target.value)} defaultValue={props.userInfo.firstName}></Input>
</FormGroup>
<FormGroup>
<Label>Last Name</Label>
<input type="text" onChange={(e: any) => setLastNameUpdated(e.target.value)} defaultValue={props.userInfo.lastName} ></input>
</FormGroup>
<FormGroup>
<Label>About me</Label>
<Input type="text" onChange={(e: any) => setUserBioUpdated(e.target.value)} defaultValue={props.userInfo.userBio}></Input>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button color="success" onClick={updateUser} className="btn-update">Update</Button>
<Button color="danger" onClick={() => props.setIsEditOpen(false)}>Cancel</Button>
</ModalFooter>
</Modal>}
</div>
)
}
export default UpdateProfile
I'm just trying to get the old value in input field (which i did), and user can choose if wants to change that or not. if not, old value should stay in updated profile, but in my case, on click 'update' it is lost in user profile.
In UpdateProfile, you should initialise the states with the value you got in props and later they could change.
const [firstNameUpdated, setFirstNameUpdated] = useState(props.userInfo.firstName)
const [lastNameUpdated, setLastNameUpdated] = useState(props.userInfo.lastName)
const [userBioUpdated, setUserBioUpdated] = useState(props.userInfo.userBio)
Initialising the state could solve all your problem.
I am designing a profile page for my site using ReactJS.
Now my question is how do I upload the image from local machine and save it to the database and also displaying it in the profile page
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { AccountAction } from '../../actions/user/AccountPg1Action';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
class AccountInfo extends Component {
constructor(props) {
super(props)
this.state = {
currentStep: 1,
userAccountData: {
userid: '',
useravtar: '',
attachement_id: '',
}
}
}
handleFileUpload = (event) => {
this.setState({useravtar: event.currentTarget.files[0]})
};
handleChange = event => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
handleSubmit = event => {
let that = this;
const { AccountAction } = that.props;
event.preventDefault();
let accountInputs = {
userid: 49,
useravtar: that.state.image,
attachement_id: 478,
}
that.setState({
userAccountData: accountInputs,
})
AccountAction(accountInputs)
}
AccountInfoView = () => {
console.log(this.state.useravtar)
return (
<section id="account_sec" className="second_form">
<div className="container">
<React.Fragment>
<Formik
initialValues={{
file: null,
email: '',
phone: ''
}}
validationSchema={accountInfoSchema}
render={(values) => {
return(
<Form onSubmit={this.handleSubmit}>
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
file= {this.state.useravtar}
handleFileUpload={this.handleFileUpload}
/>
</Form>
);
}}
/>
</React.Fragment>
)
}
render() {
return (
<div>{this.authView()}</div>
)
}
}
function Step1(props) {
console.log(props.useravtar)
if (props.currentStep !== 1) {
return null
}
return(
<div className="upload">
<label htmlFor="profile">
<div className="imgbox">
<img src="images/trans_116X116.png" alt="" />
<img src={props.useravtar} className="absoImg" alt="" />
</div>
</label>
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
<span className="guide_leb">Add your avatar</span>
</div>
)
}
When I do console in handleChange action for event.target.file[0] it responds with undefined.
Also, doing a console.log(this.state.useravtar) in handleSubmit action it shows a pathname like c:/fakepath/imgname.jpg
P.S: I have a multiple forms so I am using it in a Step wise. And i am using Redux Reducer for storing the data.
I have referred this link but my requirement is not looking like this.
Formik doesnot support fileupload by default, But you can try the following
<input id="file" name="file" type="file" onChange={(event) => {
setFieldValue("file", event.currentTarget.files[0]);
}} />
Here "file" represents the key that you are using for holding the file
And on submit you can get the filename, size etc for the file by using
onSubmit={(values) => {
console.log({
fileName: values.file.name,
type: values.file.type,
size: `${values.file.size} bytes`
})
If you want to set the file into components state then you can use
onChange={(event) => {
this.setState({"file": event.currentTarget.files[0]})};
}}
According to your code, you have to handle file upload as below
In AccountInfo add a function to handle file upload
handleFileUpload = (event) => {
this.setState({WAHTEVETKEYYOUNEED: event.currentTarget.files[0]})};
}
And pass the same function to Step1 Component as below
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
file= {this.state.image}
handleFileUpload={this.handleFileUpload}
/>
In Step1 Component where you upload the file, Change the input as
<input id="file" name="file" type="file" accept="image/*" onChange={props.handleFileUpload}/>
If you need to preview the uploaded image then you can create a blob and pass the same as source for image as below
<img src={URL.createObjectURL(FILE_OBJECT)} />
EDIT-1
As URL.createObjectURL method is deprecated due to security issues, we need to use srcObject for Media Elements, to use that you can use ref to assign srcObject, for example
Assuming you are using class Components,
Constructor
in constructor you can use
constructor(props) {
super(props)
this.imageElRef = React.createRef(null)
}
HANDLE CHANGE FUNCTION
handleFileUpload = (event) => {
let reader = new FileReader();
let file = event.target.files[0];
reader.onloadend = () => {
this.setState({
file: reader.result
});
};
reader.readAsDataURL(file);
}
Element
<img src={this.state.file} />
Here is how I resolved it with Formik and Material UI
in your JS file, just declare a variable avatarPreview like below
const [avatarPreview, setAvatarPreview] = useState('/avatars/default.png');
<Box
display='flex'
textAlign='center'
justifyContent='center'
flexDirection='column'>
<ImageAvatar size='md' src={avatarPreview || user?.avatar} />
<Button
variant='contained'
component='label'
startIcon={<CloudUploadIcon />}>
Choose Avatar
<input
name='avatar'
accept='image/*'
id='contained-button-file'
type='file'
hidden
onChange={(e) => {
const fileReader = new FileReader();
fileReader.onload = () => {
if (fileReader.readyState === 2) {
setFieldValue('avatar', fileReader.result);
setAvatarPreview(fileReader.result);
}
};
fileReader.readAsDataURL(e.target.files[0]);
}}
/>
</Button>
</Box>
Default Preview:
After choosing avatar:
You can upload single or multiple files with validation using Formik as follows:
import "./App.css";
import { useEffect, useState } from "react";
import * as Yup from "yup";
import { Formik, Field, Form, ErrorMessage, useField } from "formik";
import axios from "axios";
function App() {
return (
<Formik
initialValues={{
profile: [],
}}
validationSchema={Yup.object({
profile:Yup.array().min(1,"select at least 1 file")
})}
onSubmit={(values, props) => {
let data = new FormData();
values.profile.forEach((photo, index) => {
data.append(`photo${index}`, values.profile[index]);
});
axios
.post("you_api_for_file_upload", data, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
});
}}
>
{(formik) => {
return (
<>
<Form>
<input
id="file"
name="profile"
type="file"
onChange={(event) => {
const files = event.target.files;
let myFiles =Array.from(files);
formik.setFieldValue("profile", myFiles);
}}
multiple
/>
<ErrorMessage name="profile"/>
<button type="submit" disabled={formik.isSubmitting}>
Submit
</button>
</Form>
</>
);
}}
</Formik>
);
}
export default App;
Note: you can customize min(your choice, "your message") as per your need.
validationSchema={Yup.object({
profile:Yup.array().min(1,"select at least 1 file")
})}
FormIk does not support file uploading and we need to do it in custom way.
Just trigger onChange event and set the file.
If you face any error of setFieldValue in TypeScript, then you simply do this:
onChange={(event) => {
if (event.currentTarget.files) {
formik.setFieldValue(
"file",
event.currentTarget.files[0]
);
}
To handle file in formik with backend all you need to do add the input given below (you can change avatar to anything you want):
<input
type="file"
name="avatar"
onChange={(event) => {
setFieldValue('avatar', event.currentTarget.files[0]);
}}
/>
onSubmit you can access file using values obj like values.avatar.
On server-side (express) to access the file we use req.file
You also have to use multer that will automatically detect file to handle it on the server-side
To handle file in formik with backend all you need to do add the input given below (you can change avatar to anything you want):
<input
type="file"
name="avatar"
onChange={(event) => {
setFieldValue('avatar', event.currentTarget.files[0]);
}}
/>
onSubmit you can access file using values obj like values.avatar.
On server-side (express) to access the file we use req.file You also have to use multer & cloudinary that will detect file to handle it on the server-side
I used simple trick
<Field name="image">
{ (form , meta , value ) =>
const {setFieldValue} = form
return (
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.file[0])}
)
}
</Field>
for multiple image
<input name="image" type="file" onChange={(e) => setFieldValue(e.target.files)}
or use loop
for( i=0 ; i < e.target.file; i++){
setFieldValue([...image , e.target.file])
}