I'm making a todo list in react js. Each time a new todo item is created, some buttons are appended next to it along with a edit input text box. I'm trying to avoid using refs but purely usestate for my case, however I can't figure out how to do it. At its current state, all edit text inputs are using the same state and that brings focus loss along with other issues. I'd highly appreciate any suggetsions.
import "./theme.css"
import * as appStyles from "./styles/App.module.css"
import * as todoStyles from "./styles/Todo.module.css"
import { useState } from "react"
const initialState = [
{
id: "1",
name: "My first ToDo",
status: "new",
},
]
export function App() {
const [numofItems, setNumofItems] = useState(2)
const [newToDo, setnewToDo] = useState('');
const [todos, setTodos] = useState(initialState);
const [editTodo, setEditTodo] = useState({name: ""});
const onAddTodo = () => {
setnewToDo("");
setTodos((old) => [
...old,
{ id: numofItems.toString(), name: newToDo, status: "new" },
])
setNumofItems(numofItems + 1);
}
deleteList = () =>{
setTodos([]);
}
const handleEdit = (id, description) =>{
let el = todos.map((item) => {if(item.id === id) {item.name = description} return item});
setTodos(el);
setEditTodo('');
}
const handleMove = (id, position) =>{
const search = obj => obj.id === id;
const todoIndex = todos.findIndex(search);
if(position === "up"){
if (todos[todoIndex - 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex - 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex - 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
else if(position === "down"){
if (todos[todoIndex + 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex + 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex + 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
}
const Todo = ({ record }) => {
return <li className={todoStyles.item}>{record.name}
<button className={appStyles.editButtons} onClick={() => deleteListItem(record.id)} >Delete</button>
<button className={appStyles.editButtons} onClick={() => handleEdit(record.id, editTodo.name)}>Edit</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "down")}>Move down</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "up")}>Move up</button>
<input className={appStyles.input}
type = "text"
name={`editTodo_${record.id}`}
value = {editTodo.name}
onChange={event => {event.persist();
setEditTodo({name: event.target.value});}}
/></li>
}
const deleteListItem = (todoid) => {
setTodos(todos.filter(({id}) => id !== todoid))
}
return (
<>
<h3 className={appStyles.title}>React ToDo App</h3>
<ul className={appStyles.list}>
{todos.map((t, idx) => (
<Todo key={`todo_${idx}`} record={t} />
))}
</ul>
<div className={appStyles.actions}>
<form>
<label>
Enter new item:
<input className={appStyles.input} type="text" name="newToDo" value={newToDo} onChange={event => setnewToDo(event.target.value)}/>
</label>
</form>
<button
className={appStyles.button}
onClick={onAddTodo}
>
Add
</button>
<br></br>
<button className={appStyles.button} onClick={this.deleteList}>
Delete List
</button>
</div>
</>
)
}
Never define components in the body of another component. It will result in unmount/mount of that element every time it's rendered.
Here is how you can split up the Todo component from you App:
const Todo = ({ record, onDelete, onEdit, onMove }) => {
const [inputValue, setInputValue] = useState(record.name);
return (
<li className={todoStyles.item}>
{record.name}
<button className={appStyles.editButtons} onClick={() => onDelete()}>
Delete
</button>
<button
className={appStyles.editButtons}
onClick={() => onEdit(inputValue)}
>
Edit
</button>
<button className={appStyles.editButtons} onClick={() => onMove("down")}>
Move down
</button>
<button className={appStyles.editButtons} onClick={() => onMove("up")}>
Move up
</button>
<input
className={appStyles.input}
type="text"
value={inputValue}
onChange={(event) => {
setInputValue(event.target.value);
}}
/>
</li>
);
};
function App() {
return (
<>
<ul className={appStyles.list}>
{todos.map((t, idx) => (
<Todo
key={`todo_${idx}`}
record={t}
onDelete={() => deleteListItem(t.id)}
onEdit={(description) => handleEdit(t.id, description)}
onMove={(position) => handleMove(t.id, position)}
/>
))}
</ul>
</>
);
}
Note: I've shown only the interesting bits, not your entire code.
If you're going to do it this way I would suggest using useReducer instead of useState.
const initialState = [
{
id: "1",
name: "My first ToDo",
status: "new",
},
]
export const types = {
INIT: 'init',
NEW: 'new'
}
export default function (state, action) {
switch (action.type) {
case types.INIT:
return initialState;
case types.NEW:
return { ...state, { ...action.item } };
default:
return state;
}
}
Now in your component you can use it like this:
import {useReducer} from 'react';
import reducer, { initialState, types } from './wherever';
const [state, dispatch] = useReducer(reducer, initialState);
const handleSubmit = (event) => {
event.preventDefault();
dispatch({ type: types.NEW, item: event.target.value });
}
Related
When the user adds a value to an object that is inside an array the status is updated to added.
I'm trying to do the same thing when that value is deleted, to update the status to deleted.
const initialName = [
{
name: "",
status: "",
},
];
export default function changeNames(){
const [name, setName] = useState([initialName ]);
const handleAdd = () => {
setName([...name, ""]);
};
const handleItemChanged = (event, index) => {
const value = event.target.value;
const list = [...name];
list[index] = { name: value + "-" + id, status: "added" };
setName(list);
};
...
}
So when I add an input field and type the name, the array looks like this:
[{…}]
0:
name: "John-id"
status: "added"
When I remove John from the array, I want smth like this:
[{…}]
0:
name: "John-id"
status: "deleted"
This is the remove function
const handleRemoveClick = (index) => {
const list = [...name];
list.splice(index, 1);
setName(list);
};
<div>
{name.map((o, i) => {
return (
<tr key={"item-" + i}>
<td>
<div>
<input
type="text"
value={o.item}
onChange={(event) => handleItemChanged(event, i)}
placeholder="Name it"
/>
</div>
</td>
<td>
<button type="button" onClick={handleRemoveClick}>
Delete
</button>
</td>
</tr>
);
})}
<div>
<button Click={handleAddClick}>
Add Language
</button>
</div>
</div>
);
How can I make it work?
I think this might help you.thank you
import { useState } from "react";
import "./styles.css";
export default function App() {
const [Name, setName] = useState([]);
const [input, setInput] = useState({ name: "", status: "" });
const handleItemChanged = (event, index) => {
const { value } = event.target;
setInput({ name: value + "-id", status: "added" });
};
const addHandler = () => {
setName((prev) => {
return [...prev, input];
});
};
const removeHandler = (i) => {
const arr = [...Name];
arr[i].status = "deleted";
setName(arr);
};
return (
<div className="App">
<input type="text" name="name" onChange={(e) =>
handleItemChanged(e)} />
<button onClick={addHandler} style={{ margin: "1rem" }}>
Add
</button>
<div>
{Name &&
Name.map((data, i) => {
return (
<div key={i}>
<h3>
{data.name} {data.status}
<button
style={{ margin: "1rem" }}
onClick={() => removeHandler(i)}
>
Delete
</button>
</h3>
</div>
);
})}
</div>
</div>
);
}
You need to change the "status" property, because there is no way of removing item and setting its property.
const handleRemoveClick = (event, index) => {
const list = [...name];
list[index].status = "deleted";
setName(list);
};
And later while rendering you have to either perform a check in map function (not really elegant), or first filter your array and then map it:
// first, not elegant in my opinion
...
{name.map(item => item.status !== "deleted" ? <div>item.name</div> : null)}
// second approach
...
{name.filter(item => item.status !== "deleted").map(item => <div>item.name</div>)}
I was trying to make a ToDo Site and I wanted to save if the checkbox is checked or not in LocalStorage. But whenever I am checking the button the values inside the last are vanishing and it is not even being saved in the LocalStorage.
The following is my code:
import React from "react";
import Navbar from './components/Navbar'
import '../src/App.css'
export default function TodoInput() {
const saveLocalTasks = () => {
let savedTasks = localStorage.getItem('tasks');
console.log(savedTasks)
if (savedTasks) {
return JSON.parse(localStorage.getItem('tasks'));
} else {
return [];
}
}
const [task, setTask] = React.useState('')
// const [count, setCount] = React.useState(0)
const [taskList, setTaskList] = React.useState(saveLocalTasks)
const [disable, setDisable] = React.useState(true)
const [edit, setEdit] = React.useState(true)
const [isTaskEdit, setIsTaskEdit] = React.useState(null)
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList))
}, [taskList]);
const updateTaskList = () => {
if (task && !edit) {
setTask('')
setTaskList(
taskList.map((item) => {
if(item.key === isTaskEdit) {
return {...item, object: task}
}
setEdit(true)
return item
}
)
)
}else {
setTaskList([...taskList, {object: task, key: Date.now(), completed: false}])
setTask('')
// setCount(count + 1)
setDisable(true)
}
}
const inputValue = e => {
setTask(e.target.value)
e.target.value === '' || task === '' || task.length === 0
?
setDisable(true)
:
setDisable(false)
}
console.log(task.length)
const deleteTaskListItem = (key) => {
const updatedList = taskList.filter((item) => {
return (
item.key !== key
)
})
setTaskList(updatedList)
// setCount(count - 1)
}
const editTask = (key) => {
let newTask = taskList.find((item) => {
return (
item.key === key
)
})
console.log(newTask)
setEdit(false)
setTask(newTask.object)
setIsTaskEdit(key)
}
const boxChecked = (key) => {
let checkedTask = taskList.map((item) => {
if (item.key === key) {
taskList.completed = !taskList.completed
}
return (
task
)
})
setTaskList(checkedTask)
}
return (
<div>
<Navbar />
<header>
<div className="todolist-border">
<div className="todo-input-form">
<input
className = "inputText"
placeholder="Add a Task"
value={task}
onChange = {inputValue}
/>
{
edit
?
<button
disabled = {disable}
onClick = {updateTaskList} className="todo-add-button">
+
</button>
:
<button className="edit-button" onClick={updateTaskList}>
<i className="fas fa-edit"></i>
</button>
}
</div>
<div>
{taskList.map((item) => {
return (
<div key = {item.key} className="todolist-div">
<input type="checkbox" className="list-checkbox" id="completed"
onChange={() => boxChecked(item.key)}
checked = {item.completed}
key = {item.key}
>
</input>
<p>{item.object}</p>
<div>
<button className="edit-button" onClick={() => editTask(item.key)}>
<i className="fas fa-edit"></i>
</button>
<button onClick={()=>deleteTaskListItem(item.key)} className="delete-button">
X
</button>
</div>
</div>
)
})}
</div>
</div>
</header>
</div>
)
}
The following error occurs when I check the checkbox:
And also I whenever I click the edit button, option to edit comes on the imput box and the add button changes to edit button. I put the state setEdit(True) after the edit button click but the following error shows up whenever I click on the edit button:
Kindly check and please correct the errors in the code
The link to the site is:
https://to-do-ist.netlify.app/
The site does not have the above code, but has the bugs I mentioned(edit button and checkbox)
The code for the site is as follows:
import React from "react";
import Navbar from './components/Navbar'
import '../src/App.css'
export default function TodoInput() {
const saveLocalTasks = () => {
let savedTasks = localStorage.getItem('tasks');
console.log(savedTasks)
if (savedTasks) {
return JSON.parse(localStorage.getItem('tasks'));
} else {
return [];
}
}
const [task, setTask] = React.useState('')
const [count, setCount] = React.useState(0)
const [taskList, setTaskList] = React.useState(saveLocalTasks)
const [disable, setDisable] = React.useState(true)
const [edit, setEdit] = React.useState(true)
const [isTaskEdit, setIsTaskEdit] = React.useState(null)
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList))
}, [taskList]);
const updateTaskList = () => {
if (task && !edit) {
setTaskList(
taskList.map((item) => {
if(item.key === isTaskEdit) {
return {...item, object: task}
}
return item
})
)
}else {
setTaskList([...taskList, {object: task, key: Date.now()}])
setTask('')
setCount(count + 1)
setDisable(true)
}
// setEdit(true)
}
const inputValue = e => {
setTask(e.target.value)
e.target.value === '' || task === '' || task.length === 0
?
setDisable(true)
:
setDisable(false)
}
console.log(task.length)
const deleteTaskListItem = (key) => {
const updatedList = taskList.filter((item) => {
return (
item.key !== key
)
})
setTaskList(updatedList)
setCount(count - 1)
}
const editTask = (key) => {
let newTask = taskList.find((item) => {
return (
item.key === key
)
})
console.log(newTask)
setEdit(false)
setTask(newTask.object)
setIsTaskEdit(key)
}
return (
<div>
<Navbar />
<header>
<div className="todolist-border">
<div className="todo-input-form">
<input
className = "inputText"
placeholder="Add a Task"
value={task}
onChange = {inputValue}
/>
{
edit
?
<button
disabled = {disable}
onClick = {updateTaskList} className="todo-add-button">
+
</button>
:
<button className="edit-button" onClick={updateTaskList}>
<i className="fas fa-edit"></i>
</button>
}
</div>
<div>
{taskList.map((item) => {
return (
<div key = {item.key} className="todolist-div">
<input type="checkbox" className="list-checkbox">
</input>
<p>{item.object}</p>
<div>
<button className="edit-button" onClick={() => editTask(item.key)}>
<i className="fas fa-edit"></i>
</button>
<button onClick={()=>deleteTaskListItem(item.key)} className="delete-button">
X
</button>
</div>
</div>
)
})}
</div>
</div>
</header>
</div>
)
}
I'm trying to get the updated/newly created records and send it to the backend in "queryparam"
import React, { useState, useEffect } from "react";
//import { Container, Row, Col } from "reactstrap";
// import Box from "#mui/material/Box";
// import "bootstrap/dist/css/bootstrap.css";
// import "./index.css";
const Index = () => {
const [formValues, setFormValues] = useState([
{ orderno: 0, inputValue1: "", inputValue2: "", checked: false }
]);
const [isDisabled, setDisabled] = useState(false);
// const [inputVal1, setInputval1] = useState();
const [isChanged, setIsChanged] = useState([]);
const [error, setError] = useState(false);
const [orderNumber, setOrderNumber] = useState(1);
const addFormFields = () => {
// if (error) {
// setDisabled(false)
// }
// else {
// setDisabled(true)
// }
setFormValues((prevState) => [
...prevState,
{
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false
}
]);
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues);
setOrderNumber((prev) => prev - 1);
};
const onChangeFieldValue = (index, key, value) => {
setFormValues((prevState) => {
let copyState = [...prevState];
if (value?.length > 0) {
setError(false);
} else {
setError(true);
}
copyState[index][key] = value;
return copyState;
});
};
const saveFields = (e) => {
const queryparam = {
inputData: formValues
};
setIsChanged(queryparam);
setIsChanged((prevState, nextState) => {
let copyState = [];
if (prevState === nextState) {
copyState = [...prevState];
} else {
copyState = [...nextState];
}
return copyState;
});
console.log(isChanged, "lllllllll");
};
// useEffect(() => {
// saveFields()
// }, [isChanged])
return (
<>
{formValues.map((element, index) => (
<div className="form-inline" key={index}>
{/* <Container>
<Row>
<Col xs="12" sm="6"> */}
<label>{index + 1}</label>
<input
type="text"
value={element.inputVal1}
onChange={(e) =>
onChangeFieldValue(index, "inputValue1", e.target.value)
}
/>
<input
type="text"
value={element.inputVal2}
required
onChange={(e) =>
onChangeFieldValue(index, "inputValue2", e.target.value)
}
/>
{/* </Col>
<Col xs="12" sm="6">
<Box> */}
<button
className={`button ${error ? "add" : "btn-secondary"}`}
type="button"
disabled={error}
onClick={(e) => addFormFields(e)}
>
Add{console.log(isDisabled, "ooooooo", error)}
</button>
<button
type="button"
className="button remove"
onClick={() => removeFormFields(index)}
>
Remove
</button>
{/* </Box>
</Col>
</Row>
</Container> */}
</div>
))}
{/* <Row>
<Col sm="6" md={{ size: 4, offset: 2 }}>
<Box> */}
<button
type="button"
className="button save"
onClick={(e) => saveFields(e)}
>
Save
</button>
<button
type="button"
className="button remove"
//onClick={(e) => cancelFields(e)}
>
cancel
</button>
{/* </Box>
</Col>
</Row> */}
</>
);
};
export default Index;
https://codesandbox.io/s/black-fire-ixeir?file=/src/App.js:3662-3701
In the above link,
Step1 : when I add values for inputs "123" in input1 and "345" in input2.Then when I click on "Save" the values sent are {"input1":"123","input2":"345"}.
Step2: Again I try to add one row for inputs "456" in input1 and "678" in input2.Then when I click on save the values sent are {"input1":"456","input2":"678"}.
When I edit the existing row, for example the first row values and when I click on "Save" then only the first row value should be sent as the second row values hasn't changed.Also, If I add new rows then the newly added only should be sent if the existing row values aren't changed. Is there any way to send only the updated/newly created values to the backend using react hook
You could use a separate changes object to track changes by orderno property; saved during add/update/remove, and committed when submitting.
const [changes, setChanges] = useState({});
...
const addFormFields = () => {
const newItem = {
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false,
type: "add"
};
setFormValues((values) => [...values, newItem]);
setChanges((changes) => ({
...changes,
[newItem.orderno]: newItem
}));
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (index) => {
const item = {
...formValues[index],
type: "remove"
};
setFormValues((values) => values.filter((el, i) => i !== index));
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const onChangeFieldValue = (index, key, value) => {
const item = {
...formValues[index],
[key]: value,
type: "edit"
};
setFormValues((prevState) => {
if (value?.length > 0) {
setError(false);
const copyState = [...prevState];
copyState[index] = item;
return copyState;
} else {
setError(true);
return prevState;
}
});
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const saveFields = (e) => {
const queryparam = {
inputData: Object.values(changes)
};
console.log("Changes to commit", queryparam);
setChanges({});
};
I am building a clone of the Google Keep app with react js. I added all the basic functionality (expand the create area, add a note, delete it) but I can't seem to manage the edit part. Currently I am able to edit the inputs and store the values in the state, but how can I replace the initial input values for the new values that I type on the input?
This is Note component
export default function Note(props) {
const [editNote, setEditNote] = useState(false);
const [currentNote, setCurrentNote] = useState({
id: props.id,
editTitle: props.title,
editContent: props.content,
});
const handleDelete = () => {
props.deleteNote(props.id);
};
const handleEdit = () => {
setEditNote(true);
setCurrentNote((prevValue) => ({ ...prevValue }));
};
const handleInputEdit = (event) => {
const { name, value } = event.target;
setCurrentNote((prevValue) => ({
...prevValue,
[name]: value,
}));
};
const updateNote = () => {
setCurrentNote((prevValue, id) => {
if (currentNote.id === id) {
props.title = currentNote.editTitle;
props.content = currentNote.editContent;
} else {
return { ...prevValue };
}
});
setEditNote(false);
};
return (
<div>
{editNote ? (
<div className='note'>
<input
type='text'
name='edittitle'
defaultValue={currentNote.editTitle}
onChange={handleInputEdit}
className='edit-input'
/>
<textarea
name='editcontent'
defaultValue={currentNote.editContent}
row='1'
onChange={handleInputEdit}
className='edit-input'
/>
<button onClick={() => setEditNote(false)}>Cancel</button>
<button onClick={updateNote}>Save</button>
</div>
) : (
<div className='note' onDoubleClick={handleEdit}>
<h1>{props.title}</h1>
<p>{props.content}</p>
<button onClick={handleDelete}>DELETE</button>
</div>
)}
</div>
);
}
And this is the Container component where I am renderind the CreateArea and mapping the notes I create. I tried to map the notes again with the new values but it wasn't working.
export default function Container() {
const [notes, setNotes] = useState([]);
const addNote = (newNote) => {
setNotes((prevNotes) => {
return [...prevNotes, newNote];
});
};
const deleteNote = (id) => {
setNotes((prevNotes) => {
return prevNotes.filter((note, index) => {
return index !== id;
});
});
};
// const handleUpdateNote = (id, updatedNote) => {
// const updatedItem = notes.map((note, index) => {
// return index === id ? updatedNote : note;
// });
// setNotes(updatedItem);
// };
return (
<div>
<CreateArea addNote={addNote} />
{notes.map((note, index) => {
return (
<Note
key={index}
id={index}
title={note.title}
content={note.content}
deleteNote={deleteNote}
//handleUpdateNote={handleUpdateNote}
/>
);
})}
</div>
);
}
There are a couple of mistakes in your code.
The state properties are in the camel case
const [currentNote, setCurrentNote] = useState({
...
editTitle: props.title,
editContent: props.content,
});
But the names of the input are in lowercase.
<input
name='edittitle'
...
/>
<textarea
name='editcontent'
...
/>
Thus in handleInputEdit you don't update the state but add new properties: edittitle and editcontent. Change the names to the camel case.
In React you cant assign to the component prop values, they are read-only.
const updateNote = () => {
...
props.title = currentNote.editTitle;
props.content = currentNote.editContent;
You need to use the handleUpdateNote function passed by the parent component instead. You have it commented for some reason.
<Note
...
//handleUpdateNote={handleUpdateNote}
/>
Check the code below. I think it does what you need.
function Note({ id, title, content, handleUpdateNote, deleteNote }) {
const [editNote, setEditNote] = React.useState(false);
const [currentNote, setCurrentNote] = React.useState({
id,
editTitle: title,
editContent: content,
});
const handleDelete = () => {
deleteNote(id);
};
const handleEdit = () => {
setEditNote(true);
setCurrentNote((prevValue) => ({ ...prevValue }));
};
const handleInputEdit = (event) => {
const { name, value } = event.target;
setCurrentNote((prevValue) => ({
...prevValue,
[name]: value,
}));
};
const updateNote = () => {
handleUpdateNote({
id: currentNote.id,
title: currentNote.editTitle,
content: currentNote.editContent
});
setEditNote(false);
};
return (
<div>
{editNote ? (
<div className='note'>
<input
type='text'
name='editTitle'
defaultValue={currentNote.editTitle}
onChange={handleInputEdit}
className='edit-input'
/>
<textarea
name='editContent'
defaultValue={currentNote.editContent}
row='1'
onChange={handleInputEdit}
className='edit-input'
/>
<button onClick={() => setEditNote(false)}>Cancel</button>
<button onClick={updateNote}>Save</button>
</div>
) : (
<div className='note' onDoubleClick={handleEdit}>
<h1>{title}</h1>
<p>{content}</p>
<button onClick={handleDelete}>DELETE</button>
</div>
)}
</div>
);
}
function CreateArea() {
return null;
}
function Container() {
const [notes, setNotes] = React.useState([
{ title: 'Words', content: 'hello, bye' },
{ title: 'Food', content: 'milk, cheese' }
]);
const addNote = (newNote) => {
setNotes((prevNotes) => {
return [...prevNotes, newNote];
});
};
const deleteNote = (id) => {
setNotes((prevNotes) => {
return prevNotes.filter((note, index) => {
return index !== id;
});
});
};
const handleUpdateNote = ({ id, title, content }) => {
const _notes = [];
for (let i = 0; i < notes.length; i++) {
if (i === id) {
_notes.push({ id, title, content });
} else {
_notes.push(notes[i]);
}
}
setNotes(_notes);
};
return (
<div>
<CreateArea addNote={addNote} />
{notes.map((note, index) => {
return (
<Note
key={index}
id={index}
title={note.title}
content={note.content}
deleteNote={deleteNote}
handleUpdateNote={handleUpdateNote}
/>
);
})}
</div>
);
}
function App() {
return (
<div>
<Container />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
Also, you can store the notes in an object or hash map instead of an array. For example
const [notes, setNotes] = React.useState({
'unique_id': { title: 'Words', content: 'hello, bye' }
});
Then in handleUpdateNote you have
setNotes((prev) => ({ ...prev, unique_id: { title, content } }))
I'm new to the react and I would like to know I made a function that makes filtering depending on the boolean values
let [filterState, setFilterSTate] = useState("all");
let filteredUser = todos.filter((е) => {
if (filterState === "active") {
return !е.done;
}
if (filterState === "completed") {
return е.done;
}
return true;
});
in the console, everything is displayed, but I can't figure out how to make it work in the browser itself and only the necessary tricks are displayed
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./index.css";
const TodoList = () => {
const [newTodo, setNewTodo] = useState("");
const [todos, setTodos] = useState([
{ done: true, text: "Hey", id: 1 },
{ done: false, text: "There", id: 2 },
{ done: false, text: "Dima", id: 3 },
]);
const [id, setId] = useState(4);
const toggleDone = (id) => {
setTodos(
todos.map((todo) => ({
...todo,
done: id === todo.id ? !todo.done : todo.done,
}))
);
};
const updateTodo = (id, e) => {
setTodos(
todos.map((todo) => ({
...todo,
text: id === todo.id ? e.target.value : todo.text,
}))
);
};
const onDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
const updateNewTodo = (e) => {
setNewTodo(e.target.value);
};
const onAdd = () => {
setTodos([
...todos,
{
text: newTodo,
done: false,
id,
},
]);
setId(id + 1);
setNewTodo("");
};
let [filterState, setFilterSTate] = useState("all");
let filteredUser = todos.filter((е) => {
if (filterState === "active") {
return !е.done;
}
if (filterState === "completed") {
return е.done;
}
return true;
});
// let filteredComplited = todos.filter(function (e) {
// return e.done === true;
// });
// console.log("filteredComplited", filteredComplited);
// let filteredActive = todos.filter(function (e) {
// return e.done === false;
// });
// console.log("filteredActive", filteredActive);
// let filteredAll = todos;
// console.log("filteredAll", filteredAll);
return (
<div className="todos">
Todo List
{todos.map((todo) => (
<div key={todo.id} className="todo">
<input
type="checkbox"
value={todo.done}
onChange={() => toggleDone(todo.id)}
/>
<input
type="text"
value={todo.text}
onChange={(evt) => updateTodo(todo.id, evt)}
/>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</div>
))}
<div className="todo">
<input type="text" value={newTodo} onChange={updateNewTodo} />
<button onClick={() => onAdd()}>Add</button>
</div>
<button
onclick={() =>
todos.map((t) => `${t.done ? "x" : ""} ${t.text}`).join("\n")
}
>
Save
</button>
<button onClick={() => setFilterSTate("completed")}>Complited</button>
<button onClick={() => setFilterSTate("active")}>Active</button>
<button onClick={() => setFilterSTate("all")}>All</button>
<pre>filterState: {JSON.stringify(filterState, null, 2)}</pre>
<br />
<pre>{JSON.stringify(filteredUser, null, 2)}</pre>
</div>
);
};
ReactDOM.render(<TodoList />, document.getElementById("todos"));