I was trying to set my value in the input value! but after that, I cannot write anything in the input field! I wanted to set values from the back end in value!
We are writing an admin channel to edit the article for that we need already existing article values to edit the article! What am I doing wrong! or Maybe you can suggest a better way to edit the article in the admin channel!
here is the code:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router';
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
const [changedValues, setChangedValues] = useState('');
console.log('values', editValues);
console.log('changed', changedValues);
const params = useParams();
console.log(params);
const resultsId = params.id;
console.log('string', resultsId);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem('token') || ''
);
const setTokens = (data) => {
localStorage.setItem('token', JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/${resultsId}`
);
setEditValues(res.data);
} catch (err) {}
};
fetchData();
}, [resultsId]);
const inputValue = editValues;
const userToken = props.token;
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ''}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<input
// ref={editValues.shortDesc}
value={editValues.shortDesc}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<button type='submit'>send</button>
</form>
</div>
);
};
export default EditArticle;
your onChange handler is updating a different state property than what is being used as the value on the input (editValues vs changedValues).
Also you can pass a defaultValue to input that will get used as the default value only.
See more here https://reactjs.org/docs/uncontrolled-components.html
you can use just do it just using editValues. try this:
I just reproduced it without the api call to run the code.
import React, { useState, useEffect } from "react";
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
console.log("values", editValues);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem("token") || ""
);
const setTokens = (data) => {
localStorage.setItem("token", JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
//here get the data from api and setstate
setEditValues({ title: "title", shortDesc: "shortDesc" });
} catch (err) {}
};
fetchData();
}, []);
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ""}
onChange={(input) => setEditValues({title: input.target.value})}
type="text"
/>
<input
value={editValues.shortDesc}
onChange={(input) => setEditValues({shortDesc: input.target.value})}
type="text"
/>
<button type="submit">send</button>
</form>
</div>
);
};
export default EditArticle;
Related
I am building a simple CRUD app, and I have 90% of it working but for some reason I can't get the "edit" functionality to work. When I go to edit my team members name, nothing happens when I click "Edit Name". Worth noting, I copied the code from my "add user" component and modified were needed. Here is my code:
// EDIT USER
import React, { useState, useContext, useEffect } from 'react'
import { GlobalContext } from '../context/GlobalState'
import { Link, useNavigate, useParams } from 'react-router-dom'
import { Form, FormGroup, Label, Input, Button } from 'reactstrap'
const EditUser = (props) => {
const [selectedUser, setSelectedUser] = useState({
id: '',
name: ''
});
const { users, editUser } = useContext(GlobalContext);
const navigate = useNavigate();
const currentUserId = useParams(props);
useEffect(() => {
const userId = currentUserId;
const selectedUser = users.find((user) => user.id === userId);
if (selectedUser) {
setSelectedUser(selectedUser);
}
}, [currentUserId, users]);
const onSubmit = (e) => {
e.preventDefault()
editUser(selectedUser)
navigate('/');
}
const onChange = (e) => {
setSelectedUser({...selectedUser, [e.target.name]: e.target.value})
}
return (
<div className='container w-25'>
<Form className='form-control' onSubmit={onSubmit}>
<FormGroup>
<Label>Edit Name</Label>
<Input type='text' name='name' value={selectedUser.name} onChange={onChange} placeholder='Enter Name'></Input>
</FormGroup>
<Button type='submit'>Edit Name</Button>
<Link to='/' className='btn btn-danger m-2'>Back</Link>
</Form>
</div>
)
}
export default EditUser
// ADD USER
import React, { useState, useContext } from 'react'
import { GlobalContext } from '../context/GlobalState'
import { Link, useNavigate } from 'react-router-dom'
import { v4 as uuid } from 'uuid';
import { Form, FormGroup, Label, Input, Button } from 'reactstrap'
const AddUser = () => {
const [name, setName] = useState('');
const { addUser } = useContext(GlobalContext);
const navigate = useNavigate();
const onSubmit = (e) => {
e.preventDefault()
const newUser = {
id: uuid(),
name: name
}
addUser(newUser);
navigate('/');
}
const onChange = (e) => {
setName(e.target.value);
}
return (
<div className='container w-25'>
<Form className='form-control' onSubmit={onSubmit}>
<FormGroup>
<Label>Name</Label>
<Input
type='text'
name={name}
value={name}
onChange={onChange}
placeholder='Enter Name'></Input>
</FormGroup>
<Button type='submit'>Submit</Button>
<Link to='/' className='btn btn-danger m-2'>Back</Link>
</Form>
</div>
)
}
export default AddUser
// GLOBAL CONTEXT
import React, { createContext, useReducer } from 'react';
import AppReducer from './AppReducer';
const initialState = {
users: []
};
// Create Context \\
export const GlobalContext = createContext(initialState);
// Provider Component \\
export const GlobalProvider = ({children}) => {
const [state, dispatch] = useReducer(AppReducer, initialState);
// Actions
const removeUser = (id) => {
dispatch({
type: 'REMOVE_USER',
payload: id
});
}
const addUser = (user) => {
dispatch({
type: 'ADD_USER',
payload: user
});
}
const editUser = (user) => {
dispatch({
type: "EDIT_USER",
payload: user
});
}
return(
<GlobalContext.Provider value={{
users: state.users,
removeUser,
addUser,
editUser
}}>
{children}
</GlobalContext.Provider>
)
}
// APP REDUCER
export default (state, action) => {
switch(action.type) {
case 'REMOVE_USER':
return {
users: state.users.filter(user => {
return user.id !== action.payload
})
}
case 'ADD_USER':
return {
users: [action.payload, ...state.users]
}
case 'EDIT_USER':
const updateUser = action.payload
const updateUsers = state.users.map(user => {
if(user.id === updateUser.id) {
return updateUser;
}
return user;
})
return {
users: updateUsers
}
default:
return state
}
}
Issue
The issue seems to be that the Edit component isn't accessing the route paths params object correctly, to reference the route path's userId param.
const currentUserId = useParams();
useEffect(() => {
const userId = currentUserId;
const selectedUser = users.find((user) => user.id === userId);
if (selectedUser) {
setSelectedUser(selectedUser);
}
}, [currentUserId, users]);
Here the entire params object is named currentUserId. In the useEffect hook callback this params object is assigned to a local variable userId and then used to find a matching user object in the users array. It's comparing a specific user's id property (a string type) to the entire params object (an object type). This OFC will never be equal and selectedUser is undefined and the local selectedUser state is never initialized to the user you are trying to edit.
Solution
Either access into the params object to correctly access the specific parameter:
const currentUserId = useParams();
useEffect(() => {
const userId = currentUserId;
const selectedUser = users.find((user) => user.id === userId.userId);
if (selectedUser) {
setSelectedUser(selectedUser);
}
}, [currentUserId, users]);
Or just destructure the userId path param directly:
const { userId } = useParams();
useEffect(() => {
const selectedUser = users.find((user) => user.id === userId);
if (selectedUser) {
setSelectedUser(selectedUser);
}
}, [userId, users]);
Suggestion
Initialize the selectedUser state directly. Use a useEffect hook to check if there is a user to edit and issue a back navigation if there is not one to edit.
const EditUser = () => {
const navigate = useNavigate();
const { userId } = useParams();
const { users, editUser } = useGlobalContext(); // *
const [selectedUser, setSelectedUser] = useState(
users.find((user) => user.id === userId)
);
useEffect(() => {
if (!selectedUser) navigate(-1);
}, [navigate, selectedUser]);
const onSubmit = (e) => {
e.preventDefault();
editUser(selectedUser);
navigate("/");
};
const onChange = (e) => {
setSelectedUser({ ...selectedUser, [e.target.name]: e.target.value });
};
return (
<div className="container w-25">
{selectedUser && (
<Form className="form-control" onSubmit={onSubmit}>
<FormGroup>
<Label>Edit Name</Label>
<Input
type="text"
name="name"
value={selectedUser.name}
onChange={onChange}
placeholder="Enter Name"
/>
</FormGroup>
<Button type="submit">Edit Name</Button>
<Link to="/" className="btn btn-danger m-2">
Back
</Link>
</Form>
)}
</div>
);
};
* Note: This was just a custom hook created for convenience in the context code:
const useGlobalContext = () => useContext(GlobalContext);
i've some problems with my currency converter
err: Cannot convert undefined or null to object
const firstCurrency = Object.keys(data.rates)[0];
https://codesandbox.io/s/currency-converter-0b8t7
How can I fix it?
App.js
import React from "react";
import CurrencyConverter from "./components/CurrencyConverter";
import "./styles.css";
export default function App() {
return (
<>
<CurrencyConverter />
</>
);
}
CurrencyConverter.js
import React, { useEffect, useState } from "react";
import CurrencyRow from "./CurrencyRow";
const BASE_URL = "https://api.exchangeratesapi.io/latest";
export default function CurrencyConverter() {
const [currencyOptions, setCurrencyOptions] = useState([]);
const [fromCurrency, setFromCurrency] = useState();
const [toCurrency, setToCurrency] = useState();
const [exchangeRate, setExchangeRate] = useState();
const [amount, setAmount] = useState(1);
const [amountInFromCurrency, setAmountInFromCurrency] = useState(true);
let toAmount, fromAmount;
if (amountInFromCurrency) {
fromAmount = amount;
toAmount = amount * exchangeRate;
} else {
toAmount = amount;
fromAmount = amount / exchangeRate;
}
useEffect(() => {
fetch(BASE_URL)
.then((res) => res.json())
.then((data) => {
const firstCurrency = Object.keys(data.rates)[0];
setCurrencyOptions([data.base, ...Object.keys(data.rates)]);
setFromCurrency(data.base);
setToCurrency(firstCurrency);
setExchangeRate(data.rates[firstCurrency]);
});
}, []);
useEffect(() => {
if (fromCurrency != null && toCurrency != null) {
fetch(`${BASE_URL}?base=${fromCurrency}&symbols=${toCurrency}`)
.then((res) => res.json())
.then((data) => setExchangeRate(data.rates[toCurrency]));
}
}, [fromCurrency, toCurrency]);
function handleFromAmountChange(e) {
setAmount(e.target.value);
setAmountInFromCurrency(true);
}
function handleToAmountChange(e) {
setAmount(e.target.value);
setAmountInFromCurrency(false);
}
return (
<>
<CurrencyRow
currencyOptions={currencyOptions}
selectedCurrency={fromCurrency}
onChangeCurrency={(e) => setFromCurrency(e.target.value)}
onChangeAmount={handleFromAmountChange}
amount={fromAmount}
/>
<CurrencyRow
currencyOptions={currencyOptions}
selectedCurrency={toCurrency}
onChangeCurrency={(e) => setToCurrency(e.target.value)}
onChangeAmount={handleToAmountChange}
amount={toAmount}
/>
</>
);
}
CurrencyRow.js
import React from "react";
export default function CurrencyRow(props) {
const {
currencyOptions,
selectedCurrency,
onChangeCurrency,
onChangeAmount,
amount
} = props;
return (
<div>
<select
className="CurrencyRow"
value={selectedCurrency}
onChange={onChangeCurrency}
>
{currencyOptions.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<input
type="number"
className="input"
value={amount}
onChange={onChangeAmount}
/>
</div>
);
}
As I can see from your codepen, your data is missing a rates property right now. Currently the data object contains the following error 'You have not supplied an API Access Key. [Required format: access_key=YOUR_ACCESS_KEY]' and no rates.
That is why your Object.keys(data.rates)[0]; fails.
To fix it you need to figure out the API key problem, but also to avoid possible errors in the future, I would add a guard to your call. Something like this:
.then((data) => {
if (!data || !data.rates) return // <-- this here
const firstCurrency = Object.keys(data.rates)[0];
setCurrencyOptions([data.base, ...Object.keys(data.rates)]);
setFromCurrency(data.base);
setToCurrency(firstCurrency);
setExchangeRate(data.rates[firstCurrency]);
});
your fetch request failed with the following respose:
{
success: false,
error: {
code: 101,
type: "missing_access_key",
info: "You have not supplied an API Access Key. [Required format: access_key=YOUR_ACCESS_KEY]"
}
}
as you see there is no rates field in the response
So basically I'm trying to create a code that allows me to update the slug with the use of params.
Don't know why My code throws this error.
"TypeError: Cannot read property 'params' of undefined in react".
I tried replacing
useEffect(() => {
loadCategory();
}, []);
with
useEffect(() => {
if(match.params.slug) loadOrders()
}, [match.params.slug])
but it still didn't work.
This is the code I wrote.
import React, { useState, useEffect } from "react";
import {
HistoryContainer,
HistoryBg,
TextContainer2,
TextContainer3,
Text,
CatForm,
FormLabel,
FormControl,
ButtonPrimary,
} from "./CategoryUpdateElements";
import AdminNav from "../AdminNav/index";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
import { getCategory, updateCategory } from "../../../functions/category";
const CategoryUpdate = ({ history, match }) => {
const { user } = useSelector((state) => ({ ...state }));
const [name, setName] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
loadCategory();
}, []);
const loadCategory = () =>
getCategory(match.params.slug).then((c) => setName(c.data.name));
const handleSubmit = (e) => {
e.preventDefault();
// console.log(name);
setLoading(true);
updateCategory(match.params.slug, { name }, user.token)
.then((res) => {
// console.log(res)
setLoading(false);
setName("");
toast.success(`"${res.data.name}" is updated`);
history.push("/admin/category");
})
.catch((err) => {
console.log(err);
setLoading(false);
if (err.response.status === 400) toast.error(err.response.data);
});
};
return (
<>
<HistoryContainer>
<HistoryBg>
<AdminNav />
<TextContainer2>
<TextContainer3>
{loading ? <Text>Loading..</Text> : <Text>Update category</Text>}
<CatForm onSubmit={handleSubmit}>
<FormLabel>Name</FormLabel>
<FormControl
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
required
/>
<ButtonPrimary>Save</ButtonPrimary>
</CatForm>
</TextContainer3>
</TextContainer2>
</HistoryBg>
</HistoryContainer>
</>
);
};
export default CategoryUpdate;
UPDATE:
To add context to this problem. This code lets me update the name of the slug, but the TypeError doesn't let me follow through with this haha. I was actually following a tutorial regarding this and obviously, his code works. I was sure that I was following it properly as I wrote the code exactly like his but the only difference is my ui.
I also tried console logging match and after checking it out, what I saw was "undefined" which is not surprising.. It should have shown me the slug but instead it gave me "undefined".
This is his code which allows him to update his slug.
import React, { useState, useEffect } from "react";
import AdminNav from "../../../components/nav/AdminNav";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
import { getCategory, updateCategory } from "../../../functions/category";
const CategoryUpdate = ({ history, match }) => {
const { user } = useSelector((state) => ({ ...state }));
const [name, setName] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
loadCategory();
}, []);
const loadCategory = () =>
getCategory(match.params.slug).then((c) => setName(c.data.name));
const handleSubmit = (e) => {
e.preventDefault();
// console.log(name);
setLoading(true);
updateCategory(match.params.slug, { name }, user.token)
.then((res) => {
// console.log(res)
setLoading(false);
setName("");
toast.success(`"${res.data.name}" is updated`);
history.push("/admin/category");
})
.catch((err) => {
console.log(err);
setLoading(false);
if (err.response.status === 400) toast.error(err.response.data);
});
};
const categoryForm = () => (
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>Name</label>
<input
type="text"
className="form-control"
onChange={(e) => setName(e.target.value)}
value={name}
autoFocus
required
/>
<br />
<button className="btn btn-outline-primary">Save</button>
</div>
</form>
);
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-2">
<AdminNav />
</div>
<div className="col">
{loading ? (
<h4 className="text-danger">Loading..</h4>
) : (
<h4>Update category</h4>
)}
{categoryForm()}
<hr />
</div>
</div>
</div>
);
};
export default CategoryUpdate;
Still new to coding. Hope you guys can help me with this ^_^
I think your problem with match which is getting as the props. If you are having trouble with handle match props please try
useRouteMatch instaed.
import { useRouteMatch } from "react-router-dom";
function YourComponent() {
let match = useRouteMatch();
// Do whatever you want with the match...
return <div />;
}
I think this is more convinent to use.
For more examples
As the query will fetch the value that is provided in useState. But I want the search bar to search for recipes provided by me. Can anybody help me on how I can do that.
import React, { useEffect, useState } from 'react';
import Recipe from './Recipe';
import './App.css';
const App = ()=>{
const APP_ID= '2*****'
const APP_KEY= 'f******************'
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState('chicken');
useEffect(() =>{
const getRecipes = async()=>{
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await response.json();
setRecipes(data.hits)
};
getRecipes();
},[query]);
const updateSearch = e=>{
setSearch(e.target.value);
}
const getSearch = e =>{
setQuery(search);
setSearch('');
}
return(
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input className="search-bar" type="text" value={search} onChange={updateSearch} />
<button className="search-button" type="submit">Search</button>
</form>
{recipes.map(recipe =>(
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image} />
))}
</div>
)
}
export default App;
don't create multiple states for the same thing.
pass search string to the fetch API
import React, { useState, useEffect } from "react";
import "./styles.css";
const App = () => {
const APP_ID = "2***********";
const APP_KEY = "f*********";
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
useEffect(() => {
try {
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=${search}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json();
setRecipes(data.hits);
};
getRecipes();
} catch (error) {
// handle error here
console.error(error);
}
}, [search]);
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
setSearch("");
};
return (
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input
className="search-bar"
type="text"
value={search}
onChange={updateSearch}
/>
<button className="search-button" type="submit">
Search
</button>
</form>
{recipes.map((recipe) => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
/>
))}
</div>
);
};
export default App;
edit:
If initially, you want to have chicken results from API, change the response variable to this:
const response = await fetch(
`https://api.edamam.com/search?q=${search || "chicken"}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
I have this React component that I use to update business entities. It basically fetches by ID on componentDidMount and sends a put request when the form is submitted. I would like to refactor this to a hook based component.
Here is the code before
import React from "react";
import axios from "axios";
//Api Helper Methods
const API_HOST = "https://api.example.com";
const get = (endPoint) =>
axios
.get(`${API_HOST}/${endPoint}`)
.then((response) => response.data);
export const put = (endPoint, payload, id) =>
axios
.put(`${API_HOST}/${endPoint}/${id}`, payload)
.then((response) => response.data);
//React route (uses React Router)
const END_POINT = `users`;
class Entity extends React.Component {
state = { entity: {}, fetching: true };
getEntity = async () => {
const { id } = this.props.match.params;
this.setState({ fetching: true });
const entity = await get(`${END_POINT}/${id}`);
this.setState({ entity, fetching: false });
};
onChange = (key, value) =>
this.setState({ entity: { ...this.state.entity, [key]: value } });
componentDidMount() {
this.getEntity();
}
onSubmit = async (e) => {
e.preventDefault();
let { entity } = this.state;
let { match } = this.props;
await put(END_POINT, entity, match.params.id);
};
render() {
const { entity, fetching } = this.state;
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={this.onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => this.onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}
}
export default Entity;
This is what I have so far for the code after. Next step would be to extract custom hook.
const END_POINT = `users`;
export default function Entity({ match }) {
const [entity, setEntity] = useState({ name: "" });
const [fetching, setFetching] = useState( true );
const { id } = match.params;
const onChange = (key, value) => setEntity({ ...entity, [key]: value });
useEffect(() => {
const fetchEntity = async () => {
const entity = await get(`${END_POINT}/${id}`);
setEntity(entity);
setFetching(false);
};
fetchEntity();
}, [id]);
const onSubmit = async (e) => {
e.preventDefault();
await put(END_POINT, entity, id);
};
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}
I haven't tested this but this should be close to what you want with a custom hook for your entity function.
import React, { useEffect, useState } from 'react';
const API_HOST = "https://api.example.com";
const END_POINT = `users`;
function useEntity(entityID) {
const [entity, setEntity] = useState({})
useEffect(() => {
(async () => {
await fetch(`${API_HOST}/${END_POINT}/${props.match.params}`)
.then(async res => await res.json())
.then(result => setEntity(result));
})();
}, [])
return entity
}
export default function Entity(props) {
const { id } = props.match;
const entity = useEntity(id);
const onSubmit = async () => await fetch(`${API_HOST}/${END_POINT}/${id}`, {method: 'PUT', body: entity})
if (!entity) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => setEntity({ ...entity, name: e.target.value})}
/>
<button type="submit">submit</button>
</form>
)
}
Thanks for the help Harben, I got it working like this.
import React, {useEffect, useState} from "react";
import axios from "axios";
//Api Helper Methods
const API_HOST = "https://api.example.com";
const get = (endPoint) =>
axios.get(`${API_HOST}/${endPoint}`).then((response) => response.data);
export const put = (endPoint, payload, id) =>
axios
.put(`${API_HOST}/${endPoint}/${id}`, payload)
.then((response) => response.data);
const END_POINT = `users`;
const useEntity = (entityId) => {
const [entity, setEntity] = useState({ name: "" });
const [fetching, setFetching] = useState(true);
useEffect(() => {
(async () => {
const entity = await get(`${END_POINT}/${entityId}`);
setEntity(entity);
setFetching(false);
})();
}, [entityId]);
return [entity, fetching, setEntity];
};
//React route (uses React Router)
export default function Entity({ match }) {
const { id } = match.params;
const [entity, fetching, setEntity] = useEntity(id);
const onChange = (key, value) => setEntity({ ...entity, [key]: value });
const onSubmit = async (e) => {
e.preventDefault();
await put(END_POINT, entity, id);
};
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}