Как я могу неизменно обновлять массив состояний Redux с помощью Typescript

Я пытаюсь изучить 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, но ни один из их методов не работает в моей проблеме. Спасибо за ответы заранее! :)

Обновлено: я забыл добавить показанные ошибки, так что вот он

Вы не сказали, какую ошибку вы получаете или какое неправильное поведение вы видите в своем приложении. Можете ли вы предоставить более подробную информацию о том, что не работает?

Jimmy 26.01.2023 06:03

Также обратите внимание, что при использовании Redux Toolkit неизменяемость происходит автоматически, даже когда вы пишете изменяемый код. Так что можете просто написать state.todoCard.push(action.payload).

Guillaume Brunerie 26.01.2023 16:32

Пожалуйста, не загружайте изображения кода или ошибок. См. meta.stackoverflow.com/questions/285551/…

Jimmy 26.01.2023 19:28
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
3
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
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,

Другие вопросы по теме