1
\$\begingroup\$

I wanted to use Redux to manage the state of my KendoUI components such as the grid. The online examples from Telerik do not seem to contain clear information on how to do this, so, I started to create a solution of my own. Whilst all my code works with no errors, I'd still like it to be sanity checked by people with more experience in React and Redux as I'm relatively new.

Setup

  • ASP.NET Core 2.2
  • React with Redux
  • Thunk Middleware
  • MaterialUI
  • Kendo React

Process

  • Grid component is loaded
  • Props referenced from componentDidMount for dispatch
  • Dispatch made in mapDispatchToProps to fetch data
  • Grid is populated by returned data in payload.

src/components/vessels/VesselsContainer.js

import React from 'react';
import { connect } from 'react-redux';
import { Grid, GridColumn as Column, GridToolbar } from '@progress/kendo-react-grid';
import { fetchVessels } from '../../store/actions/vesselGridActions';
import AddIcon from '@material-ui/icons/Add';
import Fab from '@material-ui/core/Fab';

class VesselsContainer extends React.Component {
    componentDidMount() {
        this.props.getstuff();
    }
    render() {
        //handle errors and loading state
        if (this.props.error) {
            return <div>Error! {this.props.error.message}</div>;
        }
        if (this.props.loading) {
            return <div>Loading...</div>;
        }
        return (
            <div>
                <Grid data={this.props.vesselGridData} sortlable pageable pageSize={10}>
                    <Column field="VesselName" title="Name" />
                    <Column field="IMO" title="IMO" />
                    <Column field="CreatedDate" title="Created" />
                </Grid>
            </div>
        );
    }
}
const mapStateToProps = state => ({
    vesselGridData: state.fetchVessels.vesselGridData,
    loading: state.fetchVessels.loading,
    error: state.fetchVessels.error
})
const mapDispatchToProps = (dispatch) => {
    return {
        getstuff: () => dispatch(fetchVessels())
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(VesselsContainer);

src/store/actions/vesselGridActions.js

import { toDataSourceRequestString, translateDataSourceResultGroups } from '@progress/kendo-data-query';
export const FETCH_VESSELS_BEGIN = 'FETCH_VESSEL_BEGIN';
export const FETCH_VESSELS_SUCCESS = 'FETCH_VESSEL_SUCCESS';
export const FETCH_VESSELS_FAILURE = 'FETCH_VESSEL_FAILURE';

//Seem to be required by Kendo
const dataState = {
    skip: 0,
    take: 20
}
export const actionCreators = {
    fetchVesselsBegin: () => ({
        type: FETCH_VESSELS_BEGIN
    }),
    fetchVesselsSuccess: (vessels) => ({
        type: FETCH_VESSELS_SUCCESS,
        payload: { vessels }
    }),
    fetchVesselsFailure: (error) => ({
        type: FETCH_VESSELS_FAILURE,
        payload: { error }
    })   
};

export function fetchVessels() {
    const queryStr = `${toDataSourceRequestString(dataState)}`;
    const hasGroups = dataState.group && dataState.group.length;
    const base_url = 'api/Vessel/GetVessels';
    const init = { method: 'GET', accept: 'application/json', headers: {} };

    return dispatch => {
        dispatch(actionCreators.fetchVesselsBegin);
        return fetch(`${base_url}?${queryStr}`, init)
            .then(handleErrors)
            .then(response => response.json())
            .then(({ Data }) => {
                const gridResult = ({
                    result: hasGroups ? translateDataSourceResultGroups(Data) : Data,
                    dataState
                });
                dispatch(actionCreators.fetchVesselsSuccess(gridResult));                
            })
            .catch(error => dispatch(actionCreators.fetchVesselsFailure(error)));
    };
}
// Handle HTTP errors since fetch won't.
function handleErrors(response) {
    if (!response.ok) {
        throw Error(response.statusText);
    }
    return response;
}

src/store/reducers/vesselGridReducer.js

import { FETCH_VESSELS_BEGIN, FETCH_VESSELS_SUCCESS, FETCH_VESSELS_FAILURE } from '../actions/vesselGridActions';

const initialState = {
    vesselGridData: [],
    loading: false,
    error: null
};
export const reducer = (state, action) => {
    state = state || initialState;    
    switch (action.type) {
        case FETCH_VESSELS_BEGIN:
            return {
                ...state,
                loading: true,
                error: null
            };
        case FETCH_VESSELS_SUCCESS:
            return {
                ...state,
                loading: false,
                vesselGridData: action.payload.vessels.result
            };
        case FETCH_VESSELS_FAILURE:
            return {
                ...state,
                loading: false,
                error: action.payload.error,
                vesselGridData: []
            };
        default:
            return state;
    }
}

src/store/configureStore.js

import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import * as VesselGrid from './reducers/vesselGridReducer';

export default function configureStore(history, initialState) {
    const reducers = {
        fetchVessels: VesselGrid.reducer
    };    
    const middleware = [
        thunk,
        routerMiddleware(history)
    ];
    // In development, use the browser's Redux dev tools extension if installed
    const enhancers = [];
    const isDevelopment = process.env.NODE_ENV === 'development';
    if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) {
        enhancers.push(window.devToolsExtension());
    }
    const rootReducer = combineReducers({
        ...reducers,
        routing: routerReducer
    });
    return createStore(
        rootReducer,
        initialState,
        compose(applyMiddleware(...middleware), ...enhancers)
    );
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.