reactjs - اکشن React/TypeScript/Redux/Thunk اجرا نمیشود و وضعیت بهروزرسانی نمیشود


من در تلاش هستم یک درخواست GET به یک API با استفاده از React-Redux و TypeScript انجام دهم، به این صورت که سعی میکنم با کلیک روی یک دکمه (رویداد onClick) یک اکشن که این درخواست را انجام میدهد ارسال کنم و سپس میخواهم با استفاده از ریدوسر، state را بهروزرسانی کنم و سپس state بهروزرسانی شده را در console.log ببینم، اما به نظر میرسد تنها state اولیه که در store مقداردهی شده است در کنسول نمایش داده میشود. مطمئن نیستم مشکل چیست، اما به نظر میرسد اکشن من حتی به ریدوسر من ارسال نمیشود (console.log من در اکشن اجرا نمیشود و در switch statement ریدوسر نیز دیده نمیشود). در اینجا فایلهایی هستند که در آنها خطای منطقی من وجود دارد:

ویرایش: عمل فعال میشود، console.log که زیر //EDIT نوشتم در کنسول ظاهر میشود، اما به دلایلی به reducer من ارسال نمیشود...

src/actions/movieActions.ts:

import { ActionCreator, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { IMovieState } from '../reducers/movieReducer';
import axios from 'axios';

export enum MovieActionTypes {
    ANY = 'ANY',
    GENRE = 'GENRE',
}

export interface IMovieGenreAction {
    type: MovieActionTypes.GENRE;
    property: Array<String>;
}

export type MovieActions = IMovieGenreAction;

/*<Promise<Return Type>, State Interface, Type of Param, Type of Action> */
export const movieAction: ActionCreator<ThunkAction<Promise<any>, IMovieState, any, IMovieGenreAction>> = () => {
  //EDIT
  console.log('movieAction Triggered')
  return async (dispatch: Dispatch) => {
    try {
      dispatch({
        type: MovieActionTypes.GENRE
      })
      console.log('moveActions called')
      const res = await axios.get(`https://api.themoviedb.org/3/genre/movie/list?api_key=${process.env.REACT_APP_MOVIE_API_KEY}&language=en-US`)
      dispatch({
        property: res,
        type: MovieActionTypes.GENRE
    })
  } catch (err) {
    console.log(err);
  }
} 
};

src/reducers/movieReducer.ts:

import { Reducer } from 'redux';
import { MovieActionTypes, MovieActions } from '../actions/movieActions';

export interface IMovieState {
    property: any;
    genres: any;
}

const initialMovieState: IMovieState = {
    property: null,
    genres: 'askksakd'
};

export const movieReducer: Reducer<IMovieState, MovieActions> = (
    state = initialMovieState,
    action
    ) => {
      switch (action.type) {
        case MovieActionTypes.GENRE: {
          console.log('MOVE ACTION CALLED')
          return {
            ...state,
            genres: action.property
          };
        }
        default:
          console.log('default action called')
          return state;
      }
  };

src/store/store.ts:

import { applyMiddleware, combineReducers, createStore, Store } from 'redux';
import thunk from 'redux-thunk';
import { IMovieState, movieReducer } from '../reducers/movieReducer';

// Create an interface for the application state
export interface IAppState {
  movieState: IMovieState
}

// Create the root reducer
const rootReducer = combineReducers<IAppState>({
  movieState: movieReducer
});

// Create a configure store function of type `IAppState`
export default function configureStore(): Store<IAppState, any> {
  const store = createStore(rootReducer, undefined, applyMiddleware(thunk));
  return store;
}

src/components/MovieForm.tsx (فایلی که قرار است اکشن را ارسال کند):

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Box from '@material-ui/core/Box';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import { spacing } from '@material-ui/system';
import Card from '@material-ui/core/Card';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { CardHeader, TextField, CircularProgress } from '@material-ui/core';
import { useDispatch, useSelector } from 'react-redux';
import { movieAction } from '../actions/movieActions';
import { IAppState } from '../store/store';
import axios from 'axios';


const MovieForm = () => {

  const dispatch = useDispatch()
  const getGenres = () => {
    console.log('actions dispatched')
    dispatch(movieAction)
  }

  const genres = useSelector((state: IAppState) => state.movieState.genres);

  //const [genreChoice, setGenreChoice] = useState('')

  return (
    <>
    <h1>Movie Suggester</h1>
    <Paper elevation={3}>
      <Box p={10}>
        <Card>
          <div>Hello World. </div>
          <Select onChange={() => console.log(genres)}>
            <MenuItem>
              meow
            </MenuItem>
            <br />
            <br />
          </Select>
          <Button onClick={() => {
            getGenres()
            setTimeout(function(){
              console.log(genres)
            }, 5000)
          }}>genres list</Button>
          <Button onClick={() => console.log(axios.get(`https://api.themoviedb.org/3/discover/movie?api_key=${process.env.REACT_APP_MOVIE_API_KEY}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&with_genres=35&page=1`))}>Click me</Button>
        </Card>
      </Box>
    </Paper>
    </>
  )
}


export default MovieForm

و این هم src/index.tsx است، در صورتی که مشکل اینجا باشد و من از آن بیاطلاع باشم:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom';
import './index.css';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/core/styles';
import theme from './theme';
import App from './App';
import configureStore from './store/store';

const store = configureStore();

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <ThemeProvider theme={theme}>
      {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
      <CssBaseline />
        <Router>
          <App />
        </Router>
      </ThemeProvider>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

ممنون از اینکه نگاهی به این موضوع انداختید و تلاش کردید به من کمک کنید آنچه را که قادر به دیدنش نیستم ببینم!

پاسخ شماره ۱

از dispatch(movieAction()) استفاده کنید زیرا movieAction یک تابع است که اکشن را ایجاد میکند، بنابراین شما نیاز دارید که آن را فراخوانی کرده و اکشن حاصل را ارسال کنید.