7. Tạo reducer productList, productList 1 (ok)

C:\Users\Administrator\Desktop\typescript\src\routes\index.tsx

import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import HomeRoutes from './HomeRoutes';
import ProductRoutes from './ProductRoutes';
import LoginRoutes from './LoginRoutes';
function Routes() {
  return (
    <Router>
    	<HomeRoutes />
    	<LoginRoutes />
    	<ProductRoutes />
    </Router>
  )
}
export default Routes;

C:\Users\Administrator\Desktop\typescript\src\reducer\products.tsx

import * as products from './../constants/products';
import produce from 'immer';
import * as interfaces from './../interface';
const initialState = {
  loading: false,
  productList: [] as interfaces.Product[]
}
export const ProductListReducer = (state = initialState, action) =>
  produce(state, draft => {
    switch (action.type) {
      case products.GET_PRODUCT_LIST_REQUESTED:
        draft.loading = true
        break
      case products.GET_PRODUCT_LIST_SUCCESS:
        draft.loading = false
        draft.productList = action.payload.data.products
        break
      case products.GET_PRODUCT_LIST_FAILED:
        draft.loading = false
        break
      default:
        return state
    }
  })

C:\Users\Administrator\Desktop\typescript\src\pages\Product\ProductList\index.tsx

import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import MainLayout from './../../../layouts/MainLayout';
import { TableContainer } from './ProductList.styles';
import { getProductList } from './../../../middlewares/thunks';
import * as interfaces from './../../../interface';
interface ReduxProps {
  productList: interfaces.Product[]
  getProductList(): Promise<interfaces.ResGetProduct>
}
interface Props extends ReduxProps {}
const ProductList = (props: Props) => {
	const { getProductList, productList } = props;
	useEffect(() => {
    getProductList()
  }, [getProductList])
  return (
    <MainLayout>
      <h2>Product List</h2>
      <TableContainer>
        <table className="table table-striped">
				  <thead>
				    <tr>
				      <th>#</th>
				      <th>Name</th>
				      <th>Quantity</th>
				      <th>Price</th>
				      <th>Actions</th>
				    </tr>
				  </thead>
				  <tbody>
				    <tr>
				      <th>1</th>
				      <td>Iphone</td>
				      <td>100</td>
				      <td>27,000,000 đ</td>
				      <td><a className="btn btn-primary" href="/product/1">Detail</a></td>
				    </tr>
				    <tr>
				      <th>2</th>
				      <td>Samsung</td>
				      <td>28</td>
				      <td>22,000,000 đ</td>
				      <td><a className="btn btn-primary" href="/product/2">Detail</a></td>
				    </tr>
				    <tr>
				      <th>3</th>
				      <td>Nokia</td>
				      <td>10</td>
				      <td>15,000,000 đ</td>
				      <td><a className="btn btn-primary" href="/product/3">Detail</a></td>
				    </tr>
				    <tr>
				      <th>4</th>
				      <td>Sony</td>
				      <td>44</td>
				      <td>25,000,000 đ</td>
				      <td><a className="btn btn-primary" href="/product/4">Detail</a></td>
				    </tr>
				  </tbody>
				</table>
      </TableContainer>
    </MainLayout>
  )
}
const mapStateToProps = state => ({
  productList: state.productList.productList
})
const mapDispatchToProps = {
  getProductList
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductList);

C:\Users\Administrator\Desktop\typescript\src\interface\index.tsx

import React, {ReactNode} from 'react';
import { RouteProps, RouteComponentProps } from 'react-router-dom';
export interface ReqLogin {
  username: string
  password: string
}
export interface Res {
  data: any
  message: string
}
export interface ResLoginApi extends Res {
  data: {
    access_token: string
  }
}
export interface ReduxProps {
  isAuthenticated: boolean
}
export interface Props extends ReduxProps, RouteProps {
  component: React.ComponentType < RouteComponentProps >
}
export  interface ActionRedux {
  type: any
  payload?: any
}
export interface ResLogin extends ActionRedux {
}
export interface PropsNodes {
  children: ReactNode
}
export interface Product {
  id: string
  name: string
  quantity: number
  price: number
}
export interface ResGetProductApi extends Res {
  data: {
    products: Product[]
  }
}
export interface ResGetProduct extends ActionRedux {
  payload: ResGetProductApi
}
export interface ResGetProductItemApi extends Res {
  data: {
    product: Product
  }
}
export interface ResGetProductItem extends ActionRedux {
  payload: ResGetProductItemApi
}

C:\Users\Administrator\Desktop\typescript\src\reducer\index.tsx

import { combineReducers } from 'redux';
import { AppReducer } from './app';
import { loginReducer } from './login';
import { ProductListReducer } from './products';
const rootReducer = combineReducers({
  app: AppReducer,
  login: loginReducer,
  productList: ProductListReducer
})
export default rootReducer;

C:\Users\Administrator\Desktop\typescript\src\middlewares\thunks.tsx

import { loginApi } from './../apis/user';
import { getProductListApi } from './../apis/product';
import * as actions from './../actions';
import * as interfaces from './../interface';
import { Dispatch } from 'redux';
export const login = (payload: interfaces.ReqLogin) => (dispatch:Dispatch) => {
  dispatch(actions.loginRequested());
  return loginApi(payload)
    .then(res => {
      localStorage.setItem('token', res.data.access_token)
      return dispatch(actions.loginSuccess(res))
    })
    .catch(err => Promise.reject(dispatch(actions.loginFailed(err))))
}
export const getProductList = () => dispatch => {
  dispatch(actions.getProductListRequested())
  return getProductListApi()
  .then(res => dispatch(actions.getProductListSuccess(res)))
  .catch(err => Promise.reject(dispatch(actions.getProductListFailed(err))))
}

C:\Users\Administrator\Desktop\typescript\src\actions\index.tsx

import * as types from './../constants/login';
import * as products from './../constants/products';
import * as interfaces from './../interface';
export const loginRequested = ():any => ({
  type: types.LOGIN_REQUESTED
})
export const loginSuccess = (payload:any) => ({
  type: types.LOGIN_SUCCESS,
  payload
})
export const loginFailed = (payload:any) => ({
  type: types.LOGIN_FAILED,
  payload
})
export const logout = () => ({
  type: types.LOGOUT
})
export const getProductListRequested = () => ({
  type: products.GET_PRODUCT_LIST_REQUESTED
})

export const getProductListSuccess = payload => {
  return {
    type: products.GET_PRODUCT_LIST_SUCCESS,
    payload
  }
}

export const getProductListFailed = payload => ({
  type: products.GET_PRODUCT_LIST_FAILED,
  payload
})

C:\Users\Administrator\Desktop\typescript\src\constants\products.tsx

export const GET_PRODUCT_LIST_REQUESTED = 'views/ProductList/GET_PRODUCT_LIST_REQUESTED';
export const GET_PRODUCT_LIST_SUCCESS = 'views/ProductList/GET_PRODUCT_LIST_SUCCESS';
export const GET_PRODUCT_LIST_FAILED = 'views/ProductList/GET_PRODUCT_LIST_FAILED';

C:\Users\Administrator\Desktop\typescript\src\apis\product.tsx

import * as interfaces from './../interface';
const mockProducts = [
  {
    id: '1',
    name: 'Iphone',
    quantity: 100,
    price: 27000000
  },
  {
    id: '2',
    name: 'Samsung',
    quantity: 28,
    price: 22000000
  },
  {
    id: '3',
    name: 'Nokia',
    quantity: 10,
    price: 15000000
  },
  {
    id: '4',
    name: 'Sony',
    quantity: 44,
    price: 25000000
  }
]
export const getProductListApi = (): Promise<interfaces.ResGetProductApi> =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        data: {
          products: mockProducts
        },
        message: 'Lấy sản phẩm thành công'
      })
    }, 100)
  })
export const getProductItemApi = (id: string): Promise<interfaces.ResGetProductItemApi> =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      const product = mockProducts.find(product => product.id === id)
      if (product) {
        resolve({
          data: {
            product
          },
          message: 'Lấy sản phẩm thành công'
        })
      } else {
        reject(new Error('Không tìm thấy sản phẩm'))
      }
    }, 100)
  })

Last updated

Was this helpful?