JavaScript POO and request with Axios - javascript

i am trying to send data to the DataBase with Axios and I normally do it with literal object. But i want to create an Object like this:
const Food = (foodName, proteins) => {
this.foodName = foodName;
this.proteins = proteins;
...
};
And then, set a new Object with the user values as input, something like this:
<input
id="food name"
name="foodName"
type="text"
value={inputValue.foodName}
onChange={(event) => handleChange(event)}
/>
I mean the user can add a food to his own list like:
when he click on the add button, it create a new Food object with all fields needed (proteins, bran and so...) : const pasta = Object.create(Food,name : {value: ...})
then all field are sends to the DataBase.
I know it's a little crazy and complicated. But I would like to know if it is possible to proceed like this and if it is a good practice. Or am I just bothering myself for nothing ^^
By advance, thank you!
The ReactJS code.
// import core
import React, { useState, useEffect, Fragment } from "react";
import Axios from "axios";
import Foods from "./Foods";
function FoodsAdd() {
const [food, setFood] = useState("");
const [inputValue, setInputValue] = useState("");
class Food {
constructor(foodName, proteins) {
this.foodName = foodName;
this.proteins = proteins;
}
}
// testing to set state with an Object.value
const addFood = () => {
const url = "";
Axios.post(url, food);
};
// get inputs values
const handleChange = (event) => {
event.preventDefault();
const { name, value } = event.target;
const newFood = { ...inputValue, [name]: value }; // standard way of proceeding
// what i want to do :
// const newFood = Object.create(Food, name: {value : { ...inputValue, [name]: value }}) // Or something like that
console.log(name, value);
setInputValue(newFood);
};
useEffect(() => {
setFood(inputValue);
console.log(food.foodName);
}, [inputValue]);
return (
<Fragment>
<form noValidate autoComplete="off">
<fieldset>
<legend>Nom de l aliment</legend>
<input
id="food name"
name="foodName"
type="text"
value={inputValue.test}
onChange={(event) => handleChange(event)}
/>
<label for="food name"></label>
</fieldset>
<fieldset>
<legend>Protéines</legend>
<input
id="proteins"
name="proteins"
type="number"
value={inputValue.proteins}
onChange={(event) => handleChange(event)}
/>
<label for="proteins"></label>
</fieldset>
</form>
<button>Ajouter</button>
</Fragment>
);
}
export default FoodsAdd;

Related

View config getter callback for component 'input' must be a function (received 'undefined')

Here is my code for HomeScreen.js
import React, { useState } from 'react';
const HomeScreen = (props) => {
const [searchValue, setSearchValue] = useState("");
const handleSearchInputChanges = (e) => {
setSearchValue(e.target.value);
}
const resetInputField = () => {
setSearchValue("")
}
const callSearchFunction = (e) => {
e.preventDefault();
props.search(searchValue);
resetInputField();
}
return (
<form className='search'>
<input
value={searchValue}
onChange={handleSearchInputChanges}
type="text"
/>
<input onClick={callSearchFunction}
type="submit" value="SEARCH" />
</form>
);
}
The error: 'View config getter callback for component 'input' must be a function (recieved 'undefined'). Make sure to start component names with a capital letter.
I'm assuming there is something I didnt do to allow input to work but I'm just not sure what. Any help is appreciated.

React.js: Component updates only after refreshing the page [Post request]

Hi guys still new to react, working on a small react app supposed to display pictures of hamsters.
Inside of the AddHamster component, I have a Post request that seems to be working fine; " Object are passed into Database! "
My issue is that the object only get's displayed after refreshing the page. I
need the hamster object to be displayed on the page directly after pressing the Add Button, connected to the form.
Any clue on this?
import React, {useState} from "react";
import HamsterCard from './HamsterCard'
import './AddHamster.css';
const AddHamster = () => {
const [name, setname ] = useState('')
const [age, setage ] = useState('')
const [favFood, setfavFood ] = useState('')
const [imgName, setImgName ] = useState('')
const [hamsterItems, setHamsterItems] = useState([])
async function handleAddHamster(){
const newHamster = {
name: name,
age: Number(age),
favFood: favFood,
imgName: imgName
}
console.log(newHamster, 'newHamster')
const response = await fetch('/hamsters ', {method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(newHamster)
})
const data = await response.json()
console.log(data, "this is a data response");
if (response.status === 200){
setHamsterItems([...hamsterItems,name, age, favFood, imgName])
setname('')
setage('')
setfavFood('')
setImgName('')
}
}
return(
<div className="add-todo-wrapper">
<form onSubmit={(e) => e.preventDefault()}>
<label>name
<input type="text"
name="id"
value={name}
onChange={e => setname(e.target.value)} />
</label>
<label>age
<input type="text"
name="id"
value={age}
onChange={e => setage(e.target.value)} />
</label>
<label>favFood
<input type="text"
name="id"
value={favFood}
onChange={e => setfavFood(e.target.value)} />
</label>
<label>Image
<input type="text"
name="id"
value={imgName}
onChange={e => setImgName(e.target.value)} />
</label>
<div className="message">{hamsterItems ? <p>{[...hamsterItems]}</p> : null}</div>
</form>
<button onClick={() => handleAddHamster()}>ADD</button>
<HamsterCard />
</div>
)
}
export default AddHamster;
import React, {useState, useEffect} from "react";
import './HamsterCard.css';
const HamsterCard = () => {
const [hamsters, setHamsters] = useState([])
useEffect(() => {
async function get(){
const response = await fetch('/hamsters', {method: 'GET',})
const data = await response.json()
setHamsters(data)
console.log(data)
}
get()
}, [] );
return (
<div className="container">
<div className="hamster-card">
{hamsters.map((hamster) => (
<Hamster hamster={hamster}
key={hamster.id} />
))
}
</div>
</div>
)
}
export default HamsterCard;
import React, {useState} from "react";
const Hamster = ({name, age, favFood, hamster}) => {
const [hamsterDeleted, setHamsterDeleted] = useState(false)
async function deleteHamster(id) {
const response = await fetch(`/hamsters/${id}`, { method: "DELETE" });
setHamsterDeleted(true)
}
return (
hamsterDeleted ? null : (
<div>
<button onClick={() => deleteHamster(hamster.id)}>Delete</button>
<h2>{hamster.name}</h2>
<p>Ålder:{hamster.age}</p>
<p>Favorit mat:{hamster.favFood}</p>
<img src={'./img/' + hamster.imgName} alt="hamster"/>
</div>
))
}
export default Hamster;
After changing code
setHamsterItems([...hamsterItems,name, age, favFood, imgName])
to
setHamsterItems([...hamsterItems, newHamster])
I get this error message:
In the AddHamster component when you update hamsterItems it renders the whole component but in Hamstercard you are using useEffect to fetch the latest hamsters from the database
which runs only the first time the HamsterCard component mounts to re-render the HamsterCard you have to add some dependency in useEffect of HamsterCard so this will re-render the HamesterCard every time you click add button.
for which you can send hamsterItems as props to HamsterCard and pass that to useEffect dependency array.
<HamsterCard hamsterItems={hamsterItems}/>
function HamsterCard({ hamsterItems }) {
useEffect(() => {
async function get(){
const response = await fetch('/hamsters', {method: 'GET',})
const data = await response.json()
setHamsters(data)
console.log(data)
}
get()
}, [hamsterItems] );
It's now working.. problem that Is was this line:
<div className="message">{hamsterItems ? <p>{[...hamsterItems]}</p> : null}</div>
Was trying to render an object directly into the jsx..

redux toolkit state resets

I am stuck setting a state in react redux tool kit. My objective is to set the state by capturing some information from a form.
Store
import { createSlice } from '#reduxjs/toolkit'
export const SourceSlice = createSlice({
name: 'source',
initialState: {
name : "" ,
description:"",
version:"" ,
contact :"" ,
id:"",
} ,
reducers: {
addSource: (state ,action) => {
state.name = action.payload.name
state.description = action.payload.description
state.version = action.payload.version
state.contact = action.payload.contact
state.id = action.payload.name + "-" + action.payload.version
} ,
},
})
// Action creators are generated for each case reducer function
export const { addSource ,addExtract} = SourceSlice.actions
export default SourceSlice.reducer
Form
import { useDispatch } from 'react-redux'
import {addSource } from '../../Store/SourceSlice'
import React, {useState} from 'react'
const Source = () => {
const dispatch = useDispatch("")
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [version, setVersion] = useState('');
const [contact, setContact] = useState('');
const saveSourceDetails = () => {
const payload =
{
name : name,
description : description,
version: version ,
contact: contact
}
dispatch(addSource(payload))
};
const onDataChange = (event) => {
event.preventDefault();
if( event.target.name === "name"){
setName(event.target.value)
}
if( event.target.name === "description"){
setDescription(event.target.value)
}
if( event.target.name === "version"){
setVersion(event.target.value)
}
if( event.target.name === "contactPerson"){
setContact(event.target.value)
}
}
return (
<div>
<form className="ui form" onSubmit={saveSourceDetails}>
<div className="field">
<div className="Three fields">
<div className="field">
<input
type="text"
name="name"
value={name}
placeholder="Source Name"
onChange={onDataChange}
/>
</div>
<div className="field">
<input
type="text"
name="description"
value={description}
placeholder="Source Description"
onChange={onDataChange}
/>
</div>
<div>
<select
name="version"
multiple=""
className="ui fluid dropdown"
onChange={onDataChange}
>
<option value=""></option>
<option value="v1">v1</option>
<option value="v2">v2</option>
<option value="v3">v3</option>
</select>
</div>
<div className="field">
<input
type="text"
name="contactPerson"
value={contact}
placeholder="Contact Person"
onChange={onDataChange}
/>
</div>
<button className="ui button" type="submit">
+
</button>
</div>
</div>
</form>
</div>
);
};
export default Source;
Every time when i hit the button , the data is captured, send to redux the state is set for a second and the then state is reset to initial state. I am struggling to find out what makes the tool to reset everything. Any leads would help me.
PS: I am new to javascript and react
This function is the culprit. When you send the form, this gets called. You are not preventing the default event, so the page reloads, and you lose your Redux store.
const saveSourceDetails = () => {
const payload = {
name: name,
description: description,
version: version,
contact: contact
};
dispatch(addSource(payload));
};
Here's the corrected version:
const saveSourceDetails = (e) => {
e.preventDefault();
const payload = {
name: name,
description: description,
version: version,
contact: contact
};
dispatch(addSource(payload));
};

how to conditionally render the respond from an api

I want to get input from a user and compare it with the response I am getting from API, and conditionally render the information if it match or just show a sorry message,(the API only contain 1 set of a data object including 4 value) let me know what am I missing.
here is my code
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatInput, setVatInput] = useState("");
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
const [result, setResult] = useState(false);
const handelVatState = (event) => {
setVatInput(event.target.value);
};
const closeModalHandler = () => {
setResult(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("Some URL")
.then((response) => {
setResponseVatState(response.data.response.data.VATNumber);
setResponseCountryCodeState(response.data.CountryCode);
})
.catch((error) => {
console.log(error);
});
};
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{result ? (
<div>{vatInput}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
and the error is
react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
so I get the input from the user and set it with hooks, then with Axios call get my data, then I split the string with
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
to compare with the input I have, if it's the same then render the data if not just render the sorry message
You have a couple of issues, the main of which resulting in Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. is due to an infinite loop of component re-rendering, which you force by setting state directly in the function body.
More specifically, this code:
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
force react to re-evaluate the component because you're changing its state by using setResult. When react starts rendering the new body it yet again encounters setResult which results in a new update and re-render which, as you see, leads to a never-ending loop.
Furthermore, you don't need to save the request response to the component state at all, as it is relevant just for the calculation, which is needed only in the form submit handler itself. So, you should ditch the
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
state variables altogether. The only state you need except the input value is the validation result.
Also, you have a typo: setResponseVatState(response.data.response.data.VATNumber); should be setResponseVatState(response.data.VATNumber);.
Try this:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(false);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("[URL]")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{isVatValid ? (
<div>{vatValue}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
Also, I suppose <div clicked={closeModalHandler}> should be <div onClick={closeModalHandler}>?
EDIT:
Here is your solution after comments:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(null);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(null);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("https://vat.erply.com/numbers?vatNumber=BG999999999")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
const getResultRepresentation = () => {
if (isVatValid === null) {
return null;
}
if (isVatValid) {
return (
<>
<label className="text-muted">Result: </label>
<div>{vatValue}</div>
</>
);
}
else {
return (
<div onClick={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
);
}
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
value={vatValue} // <= missing
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
{getResultRepresentation()}
</div>
);
}
export default Form;
And here is a CodeSandbox to test it out.

Dynamically creating and getting inputs

I need to dynamically add new input fields on button click as well as get the user input of those inputs in an array. This is what I have and Im not sure how to do the array. Also on the screen the components only update when I change the state. Not on button click.
This is what I have:
import React, { useState } from 'react'
const CreatePoll = () => {
const [formData, setFormData] = useState({
question: '',
options: ['hi', 'there']
});
const {
question,
options
} = formData;
const addOption = e => {
e.preventDefault();
options.push([''])
console.log(options.length);
}
const handleQuestionChange = (e) => setFormData({
...formData,
[e.target.name]: e.target.value
})
const handleOptionChange = e => setFormData({
...formData
// options: []
})
const handleSubmit = async e => {
e.preventDefault();
console.log(formData)
}
return (
<form onSubmit={handleSubmit}>
<input
placeholder="enter your question"
type="text"
onChange={handleQuestionChange}
name="question" />
{options.map(() => {
return (
<input
placeholder="option"
type="text"
onChange={handleOptionChange}
name="option" />
)
})}
<input type="button" value="Add new option" onClick={addOption} />
<input type="submit" value="Submit" />
</form>
)
}
export default CreatePoll
I tried when addOption button is clicked, I add to the options state an empty string. The length of the array updates but the components on the screen dont until I type in the input box and the state changes. Also I need to map the values of the input boxes to their respective place in the array. They should also be able to edit at any time. How is this done?
Several things are wrong here :
You don't set your state in addOption, don't modify direcly the state object, prefere to destructure array, modify it and set the state.
Your map function don't take any parameter, so it will be the same input names every time, use parameter and index to now which option to change in handleQuestionChange
Your addOption could be improved by using question property directly in you setFormData (it worked like you did it, but it seems to me more clean with this)
import React, { useState } from 'react';
const CreatePoll = () => {
const [formData, setFormData] = useState({
question: '',
options: ['hi', 'there'],
});
const {
question,
options,
} = formData;
const addOption = e => {
e.preventDefault();
const newOptions = [...options];
newOptions.push('');
setFormData({ ...formData, options: newOptions });
console.log(options.length);
};
const handleQuestionChange = e => {
setFormData({
...formData,
question: e.target.value,
});
};
const handleOptionChange = (e, index) => {
const newOptions = [...options];
newOptions[index] = e.target.value;
setFormData({
...formData,
options: newOptions,
});
};
const handleSubmit = async e => {
e.preventDefault();
console.log(formData);
};
return (
<form onSubmit={handleSubmit}>
<input
placeholder="enter your question"
type="text"
onChange={handleQuestionChange}
name="question"
/>
{options.map((opt, index) => (
<input
value={opt}
key={`option_${index}`}
placeholder="option"
type="text"
onChange={e => handleOptionChange(e, index)}
name={opt}
/>
))}
<input type="button" value="Add new option" onClick={addOption} />
<input type="submit" value="Submit" />
</form>
);
};
export default CreatePoll;
to add new options on button click you need to change this function:
const addOption = e => {
e.preventDefault();
options.push([''])
console.log(options.length);
}
to be
const addOption = e => {
e.preventDefault();
const newOptions = {...formData.options}
newOptions.concat([''])
setFormData({...formatData, options: newOptions)}
}

Categories