Я пытаюсь изучить Typescript, делая что-то простое, например, приложение Todo-List. Проблема в том, что я не могу обновить массив состояний Redux в созданном мной фрагменте (или, скорее, я не знаю, как это сделать)
Вот мой основной компонент Todolist.tsx
:
import React, { FC, ChangeEvent, FormEvent, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { update } from '../todoSlice';
import { RootState } from '../todoStore';
const TodoList: FC = () => {
// React state array for the todos
const [todos, setTodos] = useState<string[]>([]);
// Get the input from this state
const [input, changeInput] = useState<string>('');
const dispatch = useDispatch()
// Selecting the state of the todoSlice component
const selector = useSelector((state: RootState) => { return state.todoCard })
const handleChangeEvent = (event: ChangeEvent<HTMLInputElement>): void => {
event.preventDefault();
changeInput(event.target.value);
}
const addTodos = (event: FormEvent<HTMLFormElement>): void => {
event.preventDefault();
setTodos([...todos, input]);
dispatch(update(todos));
console.info("REACT: ", todos);
console.info("REDUX: ", selector);
}
const removeTodos = (index: number): void => {
let filteredArray = todos.filter((todo, todoIndex) => (
todoIndex !== index
))
setTodos(filteredArray);
}
return (
<React.Fragment>
<div className='bg-light d-inline-block text-center mt-4' style = {{ padding: '10vh', marginLeft: '4vw' }}>
<h1 className='mb-4'>Todo List</h1>
<section className='text-wrap mb-4' style = {{ overflowY: 'auto', height: '10rem' }}>
{
// Mapping thee todo-list items
todos.map((todo, index) => (
<React.Fragment key = {index}>
<div className='d-flex justify-content-between mb-3'>
<li className='d-block'>{todo}</li>
<button onClick = {() => {removeTodos(index)}}>X</button>
</div>
</React.Fragment>
))
}
</section>
<form onSubmit = {addTodos}>
<input type='text' name = "input" className='p-1 rounded border-success' onChange = {handleChangeEvent}></input>
<button type = "submit" className='ms-3 btn btn-success mb-1'>Enter</button>
</form>
</div>
</React.Fragment>
)
}
export default TodoList
и вот мой компонент среза todoSlice.ts
:
import { createSlice } from '@reduxjs/toolkit'
export const todoSlice = createSlice({
name: 'todo',
initialState: {
todoCard: [],
},
reducers: {
update: (state, action) => {
return {
// Return a copy of the array and SHOULD update the state array here "immutably"
...state,
todoCard: [
...state.todoCard,
action.payload
]
}
}
}
})
export const { update } = todoSlice.actions
export default todoSlice.reducer
Я пробовал много разных способов от Google, но ни один из их методов не работает в моей проблеме. Спасибо за ответы заранее! :)
Обновлено: я забыл добавить показанные ошибки, так что вот он
Также обратите внимание, что при использовании Redux Toolkit неизменяемость происходит автоматически, даже когда вы пишете изменяемый код. Так что можете просто написать state.todoCard.push(action.payload)
.
Пожалуйста, не загружайте изображения кода или ошибок. См. meta.stackoverflow.com/questions/285551/…
export const todoSlice = createSlice({
name: 'todo',
initialState: {
todoCard: [],
},
reducers: { // <------- "Map Object" Notation
update: (state, action) => {
Делая это, вы используете https://redux-toolkit.js.org/api/createReducer с нотацией «Map Object». Вот что говорят об этом документы redux-toolkit:
Хотя эта запись немного короче, она работает только в JavaScript, а не в TypeScript и имеет меньшую интеграцию с IDE, поэтому мы рекомендуем нотация «обратный вызов строителя» в большинстве случаев.
Поэтому я бы рекомендовал переписать это с помощью https://redux-toolkit.js.org/api/createReducer#usage-with-the-builder-callback-notation — вам также не нужно беспокоиться об изменчивости затем.
Также похоже, что могут отсутствовать некоторые аннотации типов. Если state.todoCard
представляет собой массив строк, он должен быть аннотирован соответствующим образом. В документах redux-toolkit есть много примеров, чтобы улучшить поддержку TS. Посмотрите https://redux-toolkit.js.org/tutorials/typescript, например. Среди прочего, есть версия useSelector
, которая уже знает, как типизировано ваше состояние редукции, это очень помогает.
Вам нужны типизации, ваше действие имеет тип PayloadAction<string[]>, попробуйте это
reducers: {
update: (state, action: PayloadAction<string[]>) => {
...
Вы также должны указать тип для вашего InitialState
interface InitialState {
todoCard: string[];
}
const init: InitialState = {
todoCard: [],
}
export const todoSlice = createSlice({
name: 'todo',
initialState: init,
Вы не сказали, какую ошибку вы получаете или какое неправильное поведение вы видите в своем приложении. Можете ли вы предоставить более подробную информацию о том, что не работает?