How to Show API data on React-Select - reactjs

So, I'm trying to show an Amazon country API to my React-Select component and I've tried to do this in many different ways, but I would only get as result a blank page or a white list on my Select component
The code below has only the Axios method to call the API.
What Should I do so I can show the API data on the Select component?
Here's my Form.jsx component:
import { useState, useEffect } from 'react';
import '../App.css';
import Form from 'react-bootstrap/Form';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import Button from 'react-bootstrap/Button';
import Select from 'react-select';
import Axios from 'axios';
function Forms() {
const [countries, setCountry] = useState([])
Axios.get(`https://amazon-api.sellead.com/country`)
.then(res => {
const countries = res.data;
console.log(countries)
})
return (
<Form>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridEmail">
<Form.Control type="text" name = "name" placeholder="Nome" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="email" name = "email" placeholder="E-mail" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name = "cpf" placeholder="CPF" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name = "tel" placeholder="Telefone" />
</Form.Group>
<Form.Label>País</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
<Select
/>
</Form.Group>
<Form.Label>Cidade</Form.Label>
<Form.Group as={Col} controlId="formGridPassword"> <br/>
<Select
/>
</Form.Group>
<Button variant="primary" type="submit">
Enviar
</Button>
</Row>
</Form>
);
}
export default Forms;

Hey, First of all, you have to understand that you have to store that data somewhere, The data that you received from API.
Once you store it all you need is just update that in useState([]). That you created.
Now this API you are calling must be called once only so all we need is useEffect() hook with [] an empty array as a dependency so it will only call once the function that is handling API, on initial render.
Once you have data then just loop through it using the map function and render the options.
Here is code.
App.js
import "./styles.css";
import Forms from "./Forms.js";
export default function App() {
return (
<div className="App">
<Forms />
</div>
);
}
Forms.js
import { useState, useEffect } from "react";
import Form from "react-bootstrap/Form";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import Button from "react-bootstrap/Button";
import Select from "react-select";
import Axios from "axios";
function Forms() {
// creating an useState for setting country list received from api
const [countriesList, setCountriesLits] = useState([]);
//async funtion that handling api
const getCountries = async () => {
let contries = []; // to store api data
const countryRes = await Axios.get(
`https://amazon-api.sellead.com/country`
);
countryRes.data.forEach((data) => {
contries.push(data.name);
});
// updating state
setCountriesLits(contries);
};
const handleChange = (e) => {
alert(e.target.value);
};
useEffect(() => {
getCountries();
}, []);
return (
<Form>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridEmail">
<Form.Control type="text" name="name" placeholder="Nome" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="email" name="email" placeholder="E-mail" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name="cpf" placeholder="CPF" />
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Control type="text" name="tel" placeholder="Telefone" />
</Form.Group>
<Form.Label>País</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
<select onChange={handleChange}>
{/* rendering option from the state countriesList */}
{countriesList.map((data, i) => (
<option key={i} value={data}>
{data}
</option>
))}
</select>
</Form.Group>
<Form.Label>Cidade</Form.Label>
<Form.Group as={Col} controlId="formGridPassword">
{" "}
<br />
<Select />
</Form.Group>
<Button variant="primary" type="submit">
Enviar
</Button>
</Row>
</Form>
);
}
export default Forms;
You can also visit the working code here on codesandbox
Below is the output:

All you're doing is logging the data to the console (and shadowing a variable):
const countries = res.data;
console.log(countries)
If the data needs to be set in state, set it in state (and you don't need the local variable at all):
setCountry(res.data);
You've also removed the prop from your <Select> component. Clearly you'll need that back:
<Select options={countries} />
As an aside... Names matter. There is a pluralization inconsistency here:
const [countries, setCountry] = useState([])
It's best to keep your names consistent and meaningful, otherwise you end up confusing yourself when you try to use the data. Since this is an array of values, maintain pluralization:
const [countries, setCountries] = useState([]);

Related

Form validation using React, EmailJS and Bootstrap

So I'm trying to get my form validation to work using EmailJs and Bootstrap within React for a simple contact form. I got the validation to work on the UI, however, it will still send the email even if the fields are red and required. Any idea what I'm doing wrong? I followed the examples here: https://react-bootstrap.github.io/forms/validation/ and here: https://www.emailjs.com/docs/examples/reactjs/ but it does not seem to be working correctly.
Thanks in advance for any help you can provide.
EDIT
I was able to solve this by using a handleSubmit function after my sendEmail function. Please see updated code below.
I also added a way to clear the form by setting setValidated(false); e.target.reset(); within .then() method after the user submits the form...Hopefully this will help others struggling with this.
import React, { useRef, useState } from "react";
import emailjs from "#emailjs/browser";
import Button from "react-bootstrap/Button";
import PageTitle from "../components/PageTitle";
import Form from "react-bootstrap/Form";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import FloatingLabel from "react-bootstrap/FloatingLabel";
import config from "../configData.json";
import "./Contact.scss";
export const Contact = () => {
const [validated, setValidated] = useState(false);
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
emailjs
.sendForm(
config.serviceId,
config.templateId,
"#contact-form",
config.publicKey
)
.then(
() => {
alert("Your message has been sent.");
setValidated(false);
e.target.reset();
},
(error) => {
alert("There was a problem sending your message.", error);
}
);
};
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
} else {
// alert("Message was sent!");
sendEmail(event);
}
setValidated(true);
};
return (
<>
<PageTitle title="Contact" />
<div className="container my-5">
<h2 className="mb-4">Leave a Message</h2>
<Form
noValidate
ref={form}
onSubmit={handleSubmit}
validated={validated}
id="contact-form"
>
<Row>
<Form.Group as={Col} md="12" controlId="nameValidation">
<FloatingLabel
controlId="floatingInput"
label="Name"
className="mb-3"
>
<Form.Control
type="text"
placeholder="Name"
name="user_name"
size="lg"
required
/>
<Form.Control.Feedback type="invalid">
Please enter your name.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
<Form.Group as={Col} md="12" controlId="emailValidation">
<FloatingLabel
controlId="floatingInput"
label="Email"
className="mb-3"
>
<Form.Control
type="email"
placeholder="name#example.com"
name="user_email"
size="lg"
required
/>
<Form.Control.Feedback type="invalid">
Please enter a valid email.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
<Form.Group as={Col} md="12" controlId="messageValidation">
<FloatingLabel
controlId="floatingInput"
label="Message"
className="mb-3"
>
<Form.Control
placeholder="Message"
name="user_message"
size="lg"
required
as="textarea"
rows={3}
/>
<Form.Control.Feedback type="invalid">
Please enter a message.
</Form.Control.Feedback>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</FloatingLabel>
</Form.Group>
</Row>
<Button
type="submit"
value="Send"
variant="primary"
size="lg"
className="mt-3 w-100"
>
SEND
</Button>
</Form>
</div>
</>
);
};
export default Contact;
Could you please share your HTML where you are getting this info?
Even required, you can make the type='email' required so it will validade for you.
if that still a problem (which should not be), then make an IF to validade for you.
Here is an example. You can use the function below to validade if it is an email. Send the email typed by the user via parameter.
const validateEmail = (email) => {
return String(email)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
};

Check React useState() with console.log doesn't work properly

I'm trying to get data from 2 text boxes using react useState. But when I check the console.log, it takes text letters one by one as an array.
create.js
import React, {useState} from 'react'
import { Form, Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
export default function Create() {
const[firstName, setFirstName] = useState('');
const[lastName, setLasttName] = useState('');
console.log(firstName);
console.log(lastName);
return (
<div>
<div>create</div>
<div>
<Form>
<Form.Group className="mb-3" >
<Form.Label>First Name</Form.Label>
<Form.Control type="text" name='fName'
onChange={(e)=> setFirstName(e.target.value)}
placeholder="Enter first name" />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Last Name</Form.Label>
<Form.Control type="text" name='lName'
onChange={(e)=> setLasttName(e.target.value)}
placeholder="Enter last name" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</div>
</div>
)
}
App.js
import './App.css';
import Create from './Components/create';
function App() {
return (
<div className="App">
<h2>Hello</h2>
<Create/>
</div>
);
}
export default App;
This is how the console looks like.
Console should be as shown below
The onChange function gets triggered every time the input changes. If you want it to trigger only once, when you are done typing, you can use onBlur this will assign the values only when the input field gets blurred.
Here's a sandbox for you to play with. Make sure you check the console to see when firstName gets updated https://codesandbox.io/s/pedantic-tharp-rfnxqg?file=/src/App.js
I would highly suggest that you check out React Hook Forms
import React, {useState} from 'react'
import { Form, Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
export default function Create() {
const[firstName, setFirstName] = useState('');
const[lastName, setLasttName] = useState('');
const submitForm =(e)=>{
console.log(firstName)
console.log(lastName)
e.preventDefault()
}
return (
<div>
<div>create</div>
<div>
<Form onSubmit={(e)=>submitForm(e)}>
<Form.Group className="mb-3" >
<Form.Label>First Name</Form.Label>
<Form.Control type="text" name='fName'
onChange={(e)=> setFirstName(e.target.value)}
placeholder="Enter first name" />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Last Name</Form.Label>
<Form.Control type="text" name='lName'
onChange={(e)=> setLasttName(e.target.value)}
placeholder="Enter last name" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</div>
</div>
)
}

React Multiselect package is sending [object, Object] instead of key and value

I am trying to pass data in my Django back end from react front end. I am able to pass the data using some Multi-select from react. But the problem is I am sending label and value but when I try to print my data in front end and check the data what it is passing I got the result like [object Object] instead of [mylabel MyValue]
and I just want to pass the option value. I am new to react so don't know much about setState things. Can someone help me to do this?
Or any other easy way to pass multiple data in my API it would be much appreciated like I select HD and SD then in my backend I should get both value.
#This is my react code check the deliveryOption, setDeliveryOption
import axios from "axios";
import React, { useState, useEffect } from 'react'
import { LinkContainer } from 'react-router-bootstrap'
import { Table, Button, Row, Col, Form } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import FormContainer from '../components/FormContainer'
import { MultiSelect } from "react-multi-select-component";
import Select from 'react-select';
const UPLOAD_ENDPOINT = "http://127.0.0.1:8000/api/orders/create/products/";
const options = [
{ label: "HD 🍇", value: "HD" },
{ label: "SD 🥭", value: "SD" },
{ label: "DP 🍓", value: "DP" },
];
function VendorProductCreate() {
const [file, setFile] = useState(null);
const [name, setName] = useState("");
const [price, setPrice] = useState();
const [discount, setDiscount] = useState();
const [description, setDescription] = useState("");
const [subcategory, setSubcategory] = useState("");
const [countInStock, setCountInStock] = useState();
const [deliveryOption, setDeliveryOption] = useState([]);
// const [selected, setSelected] = useState([]);
const { userInfo } = useSelector((state) => state.userLogin);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append("avatar", file);
formData.append("name", name);
formData.append("price", price);
formData.append("discount", discount);
formData.append("description", description);
formData.append("subcategory", subcategory);
formData.append("countInStock", countInStock);
formData.append("deliveryOption", deliveryOption);
// formData.append("selected", selected);
const resp = await axios.post(UPLOAD_ENDPOINT, formData, {
headers: {
"content-type": "multipart/form-data",
Authorization: `Bearer ${userInfo.token}`,
},
});
console.log(resp.status)
};
return (
<FormContainer>
<form onSubmit={handleSubmit}>
<br></br>
<Link to='/productlist/vendor'>
<Button
variant='outline-info'>Go Back</Button>
</Link>
<FormContainer>
<br></br>
<h1>Merchant Product Upload</h1></FormContainer>
<br></br>
<br></br>
<Form.Group controlId='name'>
<Form.Label><strong> Product Name </strong> </Form.Label>
<Form.Control
required
type='text'
onChange={(e) => setName(e.target.value)}
value={name}
// placeholder='Enter Name'
>
</Form.Control>
</Form.Group>
<br />
<Form.Group controlId='subcategory'>
<Form.Label>Choose a Category</Form.Label>
<Form.Select aria-label="Default select example"
required
type='text'
value={subcategory}
onChange={(e) => setSubcategory(e.target.value)}>
<option value="LPG Cylinder">LPG Cylinder</option>
<option value="LPG Gas">LPG Gas</option>
</Form.Select>
</Form.Group>
<br />
<Form.Group controlId='price'>
<Form.Label><strong>Price</strong> </Form.Label>
<Form.Control
required
type='number'
// placeholder='Enter Address'
onChange={(e) => setPrice(e.target.value)}
value={price}
>
</Form.Control>
</Form.Group>
<br />
<Form.Group controlId='discount'>
<Form.Label><strong> Set Discount (Optional) </strong> </Form.Label>
<Form.Control
type='number'
onChange={(e) => setDiscount(e.target.value)}
value={discount}
// placeholder='Enter Name'
>
</Form.Control>
</Form.Group>
<br />
<Form.Group controlId='countInStock'>
<Form.Label><strong> Stock </strong> </Form.Label>
<Form.Control
type='number'
onChange={(e) => setCountInStock(e.target.value)}
value={countInStock}
// placeholder='Enter Name'
>
</Form.Control>
</Form.Group>
<br />
<Form.Label><strong style={{marginLeft: 10}}>Product Picture</strong> </Form.Label>
<Form.Control
type='file'
id='image-file'
label='Choose File'
onChange={(e) => setFile(e.target.files[0])}
>
</Form.Control>
<br />
<Form.Group controlId='description'>
<Form.Label><strong> Description </strong> </Form.Label>
<Form.Control
required
type='text'
onChange={(e) => setDescription(e.target.value)}
value={description}
// placeholder='Enter Name'
>
</Form.Control>
</Form.Group>
<br />
{/* <Form.Group controlId='deliveryOption'>
<Form.Label>Choose a Delivery</Form.Label>
<Form.Select aria-label="Default select example"
required
multiple
type='checkbox'
onChange={(e) => setDeliveryOption(e.target.value)}>
<option value="HD">HD</option>
<option value="SD">SD</option>
</Form.Select>
</Form.Group>
<br /> */}
{/* <h1>Select Fruits</h1>
<pre>{JSON.stringify(selected)}</pre> */}
{/* <MultiSelect
options={options}
value={selected}
onChange={setSelected}
labelledBy="Select"
/> */}
<Select
isMulti
name="colors"
options={options}
className="basic-multi-select"
classNamePrefix="select"
value={deliveryOption}
onChange={setDeliveryOption}
/>
<br></br>
<FormContainer><FormContainer><FormContainer>
<Button variant='outline-primary' type="submit" className='btn-sm' >
Upload Product
</Button></FormContainer>
</FormContainer></FormContainer>
</form>
</FormContainer>
);
}
export default VendorProductCreate;
#this is backend code using Django rest
#api_view(['POST'])
#permission_classes([IsVendor])
def vendorCreateProduct(request):
data = request.data
user = request.user.vendor
print(data['deliveryOption'])
print(data['selected'])
product = Product.objects.create(
user=user,
name=data['name'],
old_price = data['price'],
discount = data['discount'],
image = data['avatar'],
countInStock = data['countInStock'],
subcategory = Subcategory.objects.get_or_create(name=data['subcategory'])[0],
description=data['description'],
delivery_option= DeliveryOption.objects.get_or_create(name=data['deliveryOption'])[0],
)
serializer = ProductSerializer(product, many=False)
return Response(serializer.data)
I just want to save some multiple choice field with multiple select option using Django and react if you know any other easy and good approach then share

How to pass a data one Component to Another Components After Form Submit

In this code, I want to get my user email in Login Component after submitting the Registration Component.
Component: Registration
import React, { useState } from 'react';
import { Button, Container, Form,Row,Col } from 'react-bootstrap';
import { useNavigate,Navigate } from 'react-router-dom';
const Register = () => {
const [data,setData] = useState({
'first_name': 'dfdf',
'last_name': '',
'email': 'maruf#mail.com',
'password': '',
'password_confirm': ''
})
let navigate = useNavigate();
const handleInputChange = (e) => {
setData({
...data,
[e.target.name]: e.target.value,
});
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(data);
navigate('/login',{replace:true,state:{email:data.email}});
}
return <>
<Container fluid={'md'}>
<Row>
<Col xs={6}>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="formBasicFirstName">
<Form.Label column >First Name</Form.Label>
<Form.Control name='first_name' value={data.first_name} onChange={handleInputChange} type="text" placeholder="First Name" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicLastName">
<Form.Label>Last Name</Form.Label>
<Form.Control name='last_name' value={data.last_name} onChange={handleInputChange} type="text" placeholder="Last Name" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control name='email' value={data.email} onChange={handleInputChange} type="email" placeholder="Enter email" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control name='password' value={data.password} onChange={handleInputChange} type="password" placeholder="Password" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword_Confirm">
<Form.Label>Password</Form.Label>
<Form.Control name='password_confirm' value={data.password_confirm} onChange={handleInputChange} type="password" placeholder="Confirm Password" />
</Form.Group>
<Button variant="primary" type='submit' onSubmit={handleSubmit} >Register</Button>
</Form>
</Col>
</Row>
</Container>
</>;
};
export default Register;
here I want to send the user email address after done the registration then send the data into the Login Components.
Component: Login
React, { useEffect, useState } from "react";
import { Button, Col, Container, Form, Row } from "react-bootstrap";
import { useLocation } from "react-router-dom";
import { Navigate, useNavigate } from "react-router-dom";
const Login = () => {
const [data,setData] = useState({
email: "",
password: "",
});
const uselocation = useLocation();
if (uselocation.state) {
if (uselocation.state.email) {
setData({
...data,
email: uselocation.state.email,
});
}
}
const handleSubmit = (e) => {
e.preventDefault();
console.log(data);
};
return (
<>
<Container fluid={'md'}>
<Row>
<Col xs={6}>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Col>
</Row>
</Container>
</>
);
};
export default Login;
after a navigate to login Component I got this error
Uncaught Error: Too many re-renders. React limits the number of
renders to prevent an infinite loop.
Wrap setData from Login component with useEffect and add location as a dependency.

How can we be able to generate another element by clicking on a button?

How can we be able to generate another element by clicking on a button? in my case I want to add another input when I click on the button.
import React from 'react';
function App() {
return (
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Control type="email" placeholder="Enter email" />
</Form.Group>
<Button variant="primary">Add another input</Button>
</Form>
);
}
export default App;
import React, { useState} from 'react';
function App() {
const [activeInput, setActiveInput] = useState(false)
const handleClick = () => {
setActiveInput(!activeInput)
}
return (
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Control type="email" placeholder="Enter email" />
</Form.Group>
{ activeInput && <input type="text" placeholder="type something "/> }
<Button variant="primary"
onClick={handleClick}
>Add another input</Button>
</Form>
);
}
export default App;

Resources