could you please help me with a simple issue? I've always been programming in React, but I was always using pure js. Recently tried to transition to TS and I hate every single bit of it, but trying to understand all this hype. Could you please just give me an example of good usage of typescript using the bit of the code that I wrote? It's a simple to-do list, but have all the problems that I encountered - and in JS it would work!
Just show me how it should be done and I will try to write the real applications after figuring out the right logic behind it.
const NoteApp = () => {
const [notes, setNotes] = useState<Array<string>>()
const [title, setTitle] = useState<string>('')
const [body, setBody] = useState<string>('')
const addNote = (e:any) => {
e.preventDefault()
setNotes([
...notes,
{ title, body }
])
setTitle('')
setBody('')
}
const removeNote = (title:any) => {
setNotes(notes.filter((note) => note.title !== title))
}
return (
<div>
<h1>Notes</h1>
{notes.map((note) => (
<div key={note.title}>
<h3>{note.title}</h3>
<p>{note.body}</p>
<button onClick={() => removeNote(note.title)}>x</button>
</div>
))}
<p>Add note</p>
<form onSubmit={addNote}>
<input value={title} onChange={(e) => setTitle(e.target.value)} />
<textarea value={body} onChange={(e) => setBody(e.target.value)}></textarea>
<button>add note</button>
</form>
</div>
)
}
Typescript is just a tool to keep you code more redeable and less buggy.
It provide you way to ensure that ~90% of something is undefinded error are gone.
In this situation you can declare shape of your note like that
type Note = {
title: string;
body: string;
};
const NoteApp = () => {
const [notes, setNotes] = useState<Array<Note>>([]);
const [title, setTitle] = useState<string>('');
const [body, setBody] = useState<string>('');
const addNote = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setNotes([...notes, { title, body }]);
setTitle('');
setBody('');
};
const removeNote = (title: string) => {
setNotes(notes.filter((note) => note.title !== title));
};
const onTileChange = (e: React.ChangeEvent<HTMLInputElement>) => setTitle(e.target.value);
const onBodyChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => setBody(e.target.value);
return (
<div>
<h1>Notes</h1>
{notes.map((note) => (
<div key={note.title}>
<h3>{note.title}</h3>
<p>{note.body}</p>
<button onClick={() => removeNote(note.title)}>x</button>
</div>
))}
<p>Add note</p>
<form onSubmit={addNote}>
<input value={title} onChange={onTileChange} />
<textarea value={body} onChange={onBodyChange} />
<button type="submit">add note</button>
</form>
</div>
);
};
Related
As a Begineer in a react,i have just implementing a dynamic array field for learning but got a problem in delete operation of removing inputs fields from the row field with passing its id in deletefunction.How to overcome this problem?
Code
import React, { useState} from "react";
import "./styles.css";
const initialValues = [
{number: "",options: ""}
];
const Newrow = (props) => {
const [number, setNumber] = useState("");
const [options, setoption] = useState([]);
const addRow = () => {
let _row = {
number: "",
options: ""
};
props.setData(_row);
};
const delrow = (i) => {
data.splice(i,2)
setData({})
}
return <div>
<input
type="number"
value={number}
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<input type="text"
className="input"
value={options}
onChange={e=>{setoption(e.target.value)}}
/>
<button
type="submit"
onClick={delrow}
className="btn btn-danger">remove</button>
</div>
};
export default function App(props) {
const [data, setData] = useState([]);
const addRow = (row) => {
setData([...data, row]);
};
return (
<div className="App">
{[...data, ...initialValues].map((row, idx) => {
return <Newrow setData={addRow} data={row} key={idx} delrow{idx} />;
})}
<button
type="submit"
onClick={() =>
addRow({number: "",options: "" })}
className="btn btn-success">Add</button>
</div>
);
}
I am trying to have a reusable component that can instantiate a dynamic component:
function EditableElement({endpoint, data, ElementFormClass}) {
const [edit, setEdit] = useState(false);
const [formData, setFormData] = useState(data);
const [deleted, setDeleted] = useState(false);
if (deleted) return (<p>X_X</p>);
if (edit) return ElementFormClass(
endpoint,
data,
setFormData,
pk => {
setDeleted(true);
},
e => setEdit(false)
)
return (
<p onClick={e => setEdit(true)}>{formData.name}</p>
)
}
function ElementFormDisplayOne({endpoint, data, cancel, updateData, deleteData}) {
const [formData, setFormData] = useState(data);
// const [deleted, setDeleted] = useState(false);
// if (deleted) return (<p style={{color: 'red'}}>DELETED</p>);
return (
<form onSubmit={e => {
e.preventDefault();
e.stopPropagation();
updateData(formData);
cancel();
}}>
<label htmlFor={formData.pk}>{formData.name}</label>
<input type="text" id={formData.pk} value={formData.name}
onChange={e => setFormData({...formData, name: e.target.value})}/>
<button type="button" onClick={cancel}>cancel</button>
<button type="submit">ok</button>
<button type="button" onClick={e => deleteData(formData.pk)}>delete</button>
</form>
)
}
It's used like this:
<div>
<h3>Gallery Form ONE</h3>
{data.map(el => <EditableElement endpoint={'update'} key={el.pk} data={el}
ElementFormClass={ElementFormDisplayOne}/>)}
</div>
<div>
<h3>Gallery Form TWO</h3>
{data2.map(el => <EditableElement endpoint={'update'} key={el.pk} data={el}
ElementFormClass={ElementFormDisplayTwo}/>)}
</div>
But it throws
Error: Rendered more hooks than during the previous render.
Is what I want possible in ReactJs?
Note: I'm not using Redux and don't intend to
Codesandbox example
Fixed your error in line 104 of your codesandbox by converting your function into an actual JSX element.
if (edit)
return (<ElementFormClass
endpoint={endpoint}
data={data}
setFormData={setFormData}
cb1 = {(pk) => setDeleted(true)}
cb2 = {(e) => setEdit(false)}
/>);
This is a common error people face in react, where they use a react component as a function rather than JSX.
[Mycode] (https://codesandbox.io/s/romantic-kowalevski-fp00l?file=/src/App.js)
I'm practicing React by making todo-list app.
I want my input empty when i hit Enter. but it didn't work.
here is my whole code :
const Todo = ({ text }) => {
return (
<div>
<span>{text}</span>
</div>
);
};
const InputText = ({ addTodo }) => {
const [txt, setTxt] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!txt) return;
addTodo(txt);
setTxt("");
};
return (
<form onSubmit={handleSubmit}>
<input type="text" onChange={(e) => setTxt(e.target.value)}></input>
</form>
);
};
function App() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
const newTodos = [...todos, text];
setTodos(newTodos);
};
return (
<>
<div className="todo-list">
{todos.map((val, idx) => {
return <Todo key={val + idx} text={val} />;
})}
<InputText addTodo={addTodo} />
</div>
</>
);
}
line 17 on the link, setTxt(""); doesn't change state of txt.
how can i fix it?
That is not a "controlled" component since you are not using the value property on the input.
Try
<input type="text" onChange={e => setTxt(e.target.value)} value={txt} />
https://reactjs.org/docs/forms.html
You actually need to set the input value to your state.
Try something like
<Input type="text" onChange={(e) => setTxt(e.target.value)} value={txt}/>
I hope it helps.
i'm actually new at react, as a part of my intro a made one web app who picks some recipes from a API, actually everything is ok, but i want to made a message of "No results found" when the item searched return no results, but i don't really know where i made this. Here some of my actually code.
App.js
const App = () => {
const APP_ID = "x";
const APP_KEY = "x";
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState('chicken');
useEffect( () => {
getRecipes()
}, [query]);
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);
console.log(data)
};
const updateSearch = e => {
setSearch(e.target.value)
};
const getSearch = e => {
e.preventDefault();
setQuery(search);
setSearch("");
};
return (
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input
placeholder="Search recipes here"
className="search-bar"
type="text"
value={search}
onChange={updateSearch}
/>
<button
className="search-button"
type="submit">
Buscar
</button>
</form>
<div className="recipes">
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingridients={recipe.recipe.ingredients}
/>
))}
</div>
</div>
);
};
export default App;
recipe.js
const Recipe = ({title,calories,image,ingridients}) => {
return (
<div className={style.quadrado}>
<h1 className={style.recipe}>{title}</h1>
<ol className={style.list}>
{ingridients.map(ingridient =>(
<li>{ingridient.text}</li>
))}
</ol>
<img className={style.images} src={image} alt=""/>
<p>Calories: {calories}</p>
</div>
);
};
export default Recipe;
i make a connection with the "Edamam" API and get a list of recipes and then render on my web app, but when there's no results i want to put a message saying "Sorry, no results found".
I read some articles here, but i confess that react is kind confuse for me yet.
Thank you for you time!
You could do:
{recipes.lenght === 0 ? (<div>Sorry, no results found</div>)
: recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingridients={recipe.recipe.ingredients}
/>
))}
You can check an example about this implementation: https://stackblitz.com/edit/react-typescript-usefetch
In my simple typescript/react app, when I'm trying to map an array of objects, I'm getting an error that property 'title' does not exist on type 'object'.
const Todo = () => {
const [todos, setTodos] = useState<object[]>([])
const [title, setTitle] = useState<string>('')
const [body, setBody] = useState<string>('')
const onSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault()
const todo = {
title: title,
body: body
}
setTodos([todo, ...todos])
setTitle('')
setBody('')
}
return (
<>
<form onSubmit={onSubmit}>
<input value={title} onChange={e => setTitle(e.target.value)} />
<input value={body} onChange={e => setBody(e.target.value)} />
<button>submit</button>
</form>
todos:
{todos.map((todo) => <div><h3>{todo.title}</h3>
<p>{todo.body}</p></div>)}
</>
);
}
It fails because you say todos are object[], but the object type has no properties associated to it. If you change it to the example bellow, it should work.
const [todos, setTodos] = useState<{title: string, body: string}[]>([])