#javascript #reactjs #redux
#javascript #reactjs #redux
Вопрос:
Я создаю приложение to-do / notes, чтобы изучить основы Redux, используя перехватчики React и Typescript.
Примечание состоит из идентификатора и значения. Пользователь может добавлять, удалять или редактировать заметку.
Механика добавления / удаления работает нормально. Но редактировать для меня сложнее, поскольку я задаюсь вопросом, как это должно быть реализовано.
Я думаю, что код моего редуктора в порядке. Проблема заключается между моим компонентом (Note.tsx) и его родительским компонентом (App.tsx).
Когда я регистрирую значение, я вижу, что новое обновленное / отредактированное значение примечания не отправляется в редуктор. В результате моя заметка не редактируется с новым значением.
Я пытался «клонировать» хранилище redux и вносить свои изменения здесь, но мне это кажется утомительным и неестественным. Должен ли я просто вызвать метод редактирования из моего компонента Note.tsx?
Есть ли чистый / обычный способ сделать это?
Вот мой код :
App.tsx
function App() {
const notes = useSelector<NotesStates, NotesStates['notes']>(((state) => state.notes));
const dispatch = useDispatch();
const onAddNote = (note: string) => {
dispatch(addNote(note));
};
const onDeleteNote = (note: NoteType) => {
dispatch(deleteNote(note));
};
const onEditNote = (note: NoteType) => {
dispatch(updateNote(note));
};
return (
<div className="home">
<NewNoteInput addNote={onAddNote} />
<hr />
<ul className="notes">
{notes.map((note) => (
<Note
updateNote={() => onEditNote(note)}
deleteNote={() => onDeleteNote(note)}
note={note}
/>
))}
</ul>
</div>
);
}
Примечание.tsx
interface NoteProps {
deleteNote(): void
updateNote(noteValue: string | number): void
note: NoteType
}
const Note: React.FC<NoteProps> = ({ deleteNote, updateNote, note: { id, value } }) => {
const [isEditing, setIsEditing] = useState(false);
const [newNoteValue, setNewNoteValue] = useState(value);
const onDeleteNote = () => {
deleteNote();
};
const onUpdateNote = () => {
updateNote(newNoteValue);
setIsEditing(false);
};
const handleOnDoubleClick = () => {
setIsEditing(true);
};
const renderBody = () => {
if (!isEditing) {
return (
<>
{!value amp;amp; <span className="empty-text">Note is empty</span>}
<span>{value}</span>
</>
);
}
return (
<input
value={newNoteValue}
onChange={(e) => setNewNoteValue(e.target.value)}
onBlur={onUpdateNote}
/>
);
};
return (
<li className="note" key={id}>
<span className="note__title">
Note n°
{id}
</span>
<div className="note__body" onDoubleClick={handleOnDoubleClick}>
{renderBody()}
</div>
<button type="button" onClick={onDeleteNote}>Delete</button>
</li>
);
};
export default Note;
и notesReducer.tsx
export interface NotesStates {
notes: Note[]
}
export interface Note {
id: number
value: string
}
const initialState = {
notes: [],
};
let noteID = 0;
export const notesReducer = (state: NotesStates = initialState, action: NoteAction): NotesStates => {
switch (action.type) {
case 'ADD_NOTE': {
noteID = 1;
return {
...state,
notes: [...state.notes, {
id: noteID,
value: action.payload,
}],
};
}
case 'UPDATE_NOTE': {
return {
...state,
notes: state.notes.map((note) => {
if (note.id === action.payload.id) {
return {
...note,
value: action.payload.value,
};
}
return note;
}),
};
}
case 'DELETE_NOTE': {
return {
...state,
notes: [...state.notes
.filter((note) => note.id !== action.payload.id)],
};
}
default:
return state;
}
};
Комментарии:
1. в вашем App.tsx у вас есть
updateNote={() => onEditNote(note)}
который выполняет функциюonEditNote
, передающую текущую заметку в качестве аргумента. Вместо этого вы должны иметьupdateNote={onEditNote}
, и в вашем Note.tsx вы должны заменитьonBlur={onUpdateNote}
наonBlur={() => onUpdateNote()}
Ответ №1:
Благодаря @secan в комментариях я выполнил эту работу, а также внес некоторые изменения.
В App.tsx :
<Note
updateNote={onEditNote}
deleteNote={() => onDeleteNote(note)}
note={note}
/>
В Note.tsx :
interface NoteProps {
deleteNote(): void
updateNote(newNote: NoteType): void // updated the signature
note: NoteType
}
// Now passing entire object instead of just the value
const onUpdateNote = (newNote: NoteType) => {
updateNote(newNote);
setIsEditing(false);
};
const renderBody = () => {
if (!isEditing) {
return (
<>
{!value amp;amp; <span className="empty-text">Note is empty</span>}
<span>{value}</span>
</>
);
}
return (
<input
value={newNoteValue}
onChange={(e) => setNewNoteValue(e.target.value)}
// modifying current note with updated value
onBlur={() => onUpdateNote({ id, value: newNoteValue })}
/>
);
};