Реагировать на редукционный реквизит не определено - PullRequest
1 голос
/ 23 февраля 2020

Я новичок в редуксе, и мне трудно найти хорошее руководство, которое использует вызовы asyn c и машинопись. Я пытался понять это сам, но я немного застрял. Если бы кто-то мог взглянуть на мой код и, возможно, дать мне обратную связь и / или предложения относительно того, как я могу решить эту проблему, я был бы очень признателен!

// types.ts file
export const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST';
export const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS';
export const FETCH_USERS_FAILURE = 'FETCH_USERS_FAILURE';

^ Здесь я определяю константы для согласованности.

// userActions.ts
import { FETCH_USERS_FAILURE, FETCH_USERS_REQUEST, FETCH_USERS_SUCCESS } from './types';
import { Dispatch } from 'redux';
import axios, { AxiosResponse } from 'axios';

export interface UserProps {
  id: number
  name: string
  email: string
}

export const fetchUsersRequest = () => {
  return {
    type: FETCH_USERS_REQUEST,
  };
};

export const fetchUsersSuccess = (users: Array<UserProps>) => {
  return {
    type: FETCH_USERS_SUCCESS,
    users: users,
  };
};

export const fetchUsersFailure = (error: string) => {
  return {
    type: FETCH_USERS_FAILURE,
    error: error,
  };
};

export const fetchUsers = () => {
  return (dispatch: Dispatch): Promise<unknown> => {
    dispatch(fetchUsersRequest());
    return axios.get('https://jsonplaceholder.typicode.com/users')
      .then((response: AxiosResponse<UserProps[]>) => {
        dispatch(fetchUsersSuccess(response.data));
        return response.data;
      })
      .catch((error: string) => {
        dispatch(fetchUsersFailure(error));
      });
  };
};

userReducer

import { UserProps } from '../actions/userActions';
import { FETCH_USERS_FAILURE, FETCH_USERS_REQUEST, FETCH_USERS_SUCCESS } from '../actions/types';

interface Action {
  type: string
  payload: Array<UserProps> | string,
}

export interface initialStateProps {
  loading: boolean,
  users: Array<UserProps>
  error: string
}

const initialState: initialStateProps = {
  loading: false,
  users: [],
  error: '',
};

export const userReducer = (state = initialState, action: Action) => {
  switch (action.type) {
    case FETCH_USERS_REQUEST:
      return {
        ...state,
        loading: true,
      };
    case FETCH_USERS_SUCCESS:
      return {
        loading: false,
        users: action.payload,
      };
    case FETCH_USERS_FAILURE:
      return {
        loading: false,
        users: [],
        error: action.payload,
      };
    default: {
      return state;
    }
  }
};

export const getUsers = (state: initialStateProps) => state.users;
export const getUsersRequest = (state: initialStateProps) => state.loading;
export const getUsersFailure = (state: initialStateProps) => state.error;

А затем для своего проекта я использую connected-router, чтобы помочь отслеживать маршруты.

import { combineReducers } from 'redux';
import { History } from 'history';
import { connectRouter } from 'connected-react-router';
import { userReducer } from './userReducers';

export const createRootReducer = (history: History) => combineReducers({
  router: connectRouter(history),
  userReducer,
});

Магазин:

import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger';
import { routerMiddleware } from 'connected-react-router';
import { createRootReducer } from './reducers';

export const history = createBrowserHistory();

const loggerMiddleware = createLogger();

export const configureStore = (preloadedState?: any) => {
  const composeEnhancer: typeof compose = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
  return createStore(
    createRootReducer(history),
    preloadedState,
    composeEnhancer(
      applyMiddleware(
        routerMiddleware(history),
        thunkMiddleware,
        loggerMiddleware,
      ),
    ),
  );
};

И в приложении я использую это:

const mapStateToProps = (state: initialStateProps) => ({
  error: getUsersFailure(state),
  users: getUsers(state),
  loading: getUsersRequest(state)
});

const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({
  fetchUsers: fetchUsers
}, dispatch);

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(TopbarNav);

Но когда я console.log(props);, я получаю:

users: undefined

loading: undefined

error: undefined

EDIT: Здесь я запускаю fetchUsers:

const TopbarNav: React.FC = (props: any) => {

  const [loading, setLoading] = React.useState(true);

  const classes = useStyles();

  useEffect(() => {
    props.fetchUsers();
  });

  const handler = () => {
    console.log({props});
  };
};

Я оставил метод рендеринга в этом вопросе.

EDIT 2 обновлен метод useEffect:

const [users, setUsers] = React.useState([]);

const [loading, setLoading] = React.useState(true);

const classes = useStyles();

useEffect(() => {
  setUsers(props.fetchUsers());
}, [users, props, loading]);

const handler = () => {
  console.log(props.loading);
};

1 Ответ

1 голос
/ 24 февраля 2020

Используя combineReducers таким образом, я думаю, что ваше состояние будет выглядеть следующим образом

{
  router: ...,
  userReducer: ...,
}

, поэтому вы можете исправить это, изменив селекторы для поиска правильных реквизитов

state.userReducer.users
state.userReducer.loading
...
...