Loading data from MongoDB into React State - reactjs

I have a problem where I can load the user data from my node server, but when I try to get the data into State in the frontend of React, I get a 404 when I call the data.
error: http://localhost:3000/users 404 (Not Found)
I have tried several approaches but it seems that my issue lies in not being able to pre-load the data from the database into State....can anyone please tell me what I'm missing?
Routes/API
// #route GET api/users
// #desc Get Users
// #access Public
router.get('/', async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
Then on the frontend, I have an action
import axios from 'axios';
import {
GET_USERS,
GET_USERS_ERROR
} from './types';
// Get users
export const getUsers = () => async (dispatch) => {
try {
const res = await axios.get('/users');
dispatch({
type: GET_USERS,
payload: res.data,
});
} catch (error) {
dispatch({
type: GET_USERS_ERROR,
payload: {
msg: error.response.status.statusText,
status: error.response.status,
},
});
}
};
My reducer file:
import {
GET_USERS,
GET_USERS_ERROR
} from '../actions/types';
const initialState = {
user: null,
users: [],
error: {},
};
export default function(state = initialState, action) {
const {
type,
payload
} = action;
switch (type) {
case GET_USERS:
return {
...state,
users: payload,
};
case GET_USERS_ERROR:
return {
...state,
error: payload,
};
default:
return state;
}
}
finally, the place where I'm trying to get the data
import React, {
useState,
useEffect
} from 'react';
import {
connect
} from 'react-redux';
import {
getUsers
} from '../../actions/users';
import PropTypes from 'prop-types';
//Bootstrap Table
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import * as ReactBootStrap from 'react-bootstrap';
const UserTable = ({
getUsers,
users
}) => {
useEffect(() => {
getUsers();
// eslint-disable-next-line
}, []);
const [loading, setLoading] = useState(false);
const columns = [{
dataField: '_id',
text: 'ID'
},
{
dataField: 'user_id',
text: "User's ID"
},
{
dataField: 'firstname',
text: 'Title of Todo'
},
{
dataField: 'lastname',
text: 'Is this done?'
},
];
return ( <
div > Hello < /div>
// <BootstrapTable
// keyField='id'
// data={users}
// columns={columns}
// pagination={paginationFactory()}
// />
);
};
const mapStateToProps = (state) => ({
users: state.users,
});
export default connect(mapStateToProps, {
getUsers
})(UserTable);

Based on this bit in you question // #route GET api/users, indicates you are likely missing /api in the FE call.
Try
const res = await axios.get('/api/users');

Related

Appending latest message from websocket using redux-saga while receving and sending latest message

I have connected a web socket through redux saga. It successfully connected through out whole app. But while receiving and sending latest message I am getting notification of that corresponding message. But I am unable to bind it in UI.
Here is my socket connection file
import {take, put, call, fork, select} from 'redux-saga/effects'
import {eventChannel} from '#redux-saga/core'
import mqtt from 'mqtt'
import publish from './publish'
import unsubscribe from './unsubrcibe'
import messagepublish from './messagepublish'
import {parseMessageType} from '../constants/parseMessageType'
import {mergeArrays} from '../constants/config'
import {notification} from 'antd'
import {displayListMessage} from '../constants/displayListMessage'
import Avatar from 'antd/lib/avatar/avatar'
const userdetail = state =>
state.auth.loginMessage || JSON.parse(localStorage.getItem('logindetails'))
const messageDet = state => state.message.messageList || []
function connect() {
let options = {
protocol: 'wss',
clientId: '',
username: 'inextrix',
password: 'inextrix',
}
const client = mqtt.connect('wss://ee.astppbilling.org:9001/wss', options)
return new Promise(resolve => {
client.on('connect', () => {
resolve(client)
})
})
}
function* read(client) {
const loguserdetail = yield select(userdetail)
client.subscribe(
[
`GetChats/${loguserdetail.user_id.user_id}`,
`GetMessages/${loguserdetail.user_id.user_id}`,
`Message/${loguserdetail.user_id.user_id}`,
],
{qos: 1},
err => {
if (err) {
return
}
}
)
const channel = yield call(subscribe, client)
let action = yield take(channel)
yield put(action)
}
function* subscribe(client) {
const loguserdetail = yield select(userdetail)
const mesdet = yield select(messageDet)
return new eventChannel(emit => {
const chatdata = (topic, message) => {
switch (topic) {
case `GetChats/${loguserdetail.user_id.user_id}`:
return emit({
type: 'GET_CHAT_LIST_SUCCESS',
payload: JSON.parse(new TextDecoder('utf-8').decode(message)),
})
case `GetMessages/${loguserdetail.user_id.user_id}`:
return emit({
type: 'RECEIVE_MESSAGE_SUCCESS',
payload: JSON.parse(new TextDecoder('utf-8').decode(message))
.messages,
})
case `Message/${loguserdetail.user_id.user_id}`:
let newreceivermessage = parseMessageType(
JSON.parse(new TextDecoder('utf-8').decode(message)),
false,
false,
false
)
notification.info({
message: newreceivermessage.name,
description: displayListMessage(
newreceivermessage.type,
newreceivermessage.payload
),
icon:
newreceivermessage.userImage !== '' ? (
<Avatar src={newreceivermessage.userImage} shape="square" />
) : (
<Avatar
src={newreceivermessage?.name?.charAt(0)}
shape="square"
/>
),
placement: 'topRight',
})
return emit({
type: 'ADD_MESSAGE_SUCCESS',
payload: newreceivermessage,
})
default:
return emit({
type: 'MQTT_CONNECT_SUCCESS',
payload: {
topic,
message: JSON.parse(new TextDecoder('utf-8').decode(message)),
},
})
}
}
client.on('message', chatdata)
return () => {}
})
}
export default function* flow() {
yield take('MQTT_CONNECT')
const client = yield call(connect)
yield fork(read, client)
yield fork(publish, client)
yield fork(messagepublish, client)
yield fork(unsubscribe, client)
}
Here I am Sending Message through socket while chatting this will concat the newmessage to existing array
import {take, call, put, fork, select} from 'redux-saga/effects'
import {parseMessageType} from '../constants/parseMessageType'
export default function* messagepublish(client) {
const {payload} = yield take('ADD_MESSAGE')
client.publish(
payload.topic,
JSON.stringify(payload.message),
{qos: 1},
err => {
if (err) {
return
}
}
)
let newreceivermessage = parseMessageType(
JSON.stringify(payload.message),
false,
false,
false
)
yield put({type: 'ADD_MESSAGE_SUCCESS', payload: newreceivermessage})
}
The list of Messages which are displaying according to design of sender and receiver in UI. I want to display the concat message in this screen without refreshing or going back
import React, {useEffect, useMemo} from 'react'
import InfiniteScroll from 'react-infinite-scroll-component'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {MQttSendMessage, MQttConnect} from '../../../redux/action/actions'
import {displayMessage} from '../../../redux/constants/displayMessage'
import '../../../App.css'
const ChatBody = props => {
const usercred = JSON.parse(localStorage.getItem('logindetails'))
useEffect(() => {
const chatbody = {
chatId: props?.chatdetail?.chatId,
opponentUid: props?.chatdetail?.senderId,
secretId: '',
dtime: -1,
messages: props.messageList,
}
props.MQttSendMessage('GetMessages', chatbody)
}, [])
return (
<div style={{height: '93vh'}}>
<InfiniteScroll
dataLength={props?.messageList?.length}
className={'chat-body-list'}
inverse={true}
hasMore={true}
>
{props.messageList.map((v, i) => (
<div
key={v.messageId}
style={{
display: 'flex',
justifyContent:
v.senderId === usercred?.user_id?.user_id
? 'flex-end'
: 'flex-start',
margin: 3,
}}
>
{displayMessage(v, usercred?.user_id?.user_id)}
</div>
))}
</InfiniteScroll>
</div>
)
}
function initMapStateToProps(state) {
return {
messageList: state.message.messageList,
}
}
function initMapDispatchToProps(dispatch) {
return bindActionCreators(
{
MQttSendMessage,
MQttConnect,
},
dispatch
)
}
export default connect(initMapStateToProps, initMapDispatchToProps)(ChatBody)
I have also message reducer which contain old message as well as new message action
const initialState = {
messageList: [],
messageErr: '',
mesageLoading: false,
}
export default (state = initialState, {type, payload}) => {
switch (type) {
case 'RECEIVE_MESSAGE_SUCCESS':
return {
messageList: payload,
messageErr: '',
mesageLoading: false,
}
case 'RECEIVE_MESSAGE_ERROR':
return {
messageList: [],
messageErr: payload,
mesageLoading: false,
}
case 'RECEIVE_MESSAGE_LOADING':
return {
messageList: [],
messageErr: '',
mesageLoading: true,
}
case 'ADD_MESSAGE_SUCCESS':
return {
messageList: state.messageList.concat(payload),
messageErr: '',
messageLoading: false,
}
default:
return state
}
}
Can anyone suggest me How can I acheive it

Async call results to Warning: Maximum update depth exceeded in React & Redux

I have an app built with React, Redux that pulls data from a RESTful service sitting in my local. I tested the implementation with dummy data and works fine. However, when I hook up the async service the calls result in havoc with the below error:
Here is the code
reducer.js
import {
LOAD_ALL_PRODUCTS_SUCCESS,
LOAD_ALL_PRODUCTS_REQUEST,
LOAD_ALL_PRODUCTS_FAIL,
LOAD_PRODUCT_REQUEST,
LOAD_PRODUCT_SUCCESS,
LOAD_PRODUCT_FAIL,
} from './actions';
export const productData = (state = { loader: {}, products: [] }, action) => {
const { type, payload } = action;
switch (type) {
case LOAD_ALL_PRODUCTS_REQUEST: {
return { loader: true, products: [] };
}
case LOAD_ALL_PRODUCTS_SUCCESS: {
return { loader: false, products: payload };
}
case LOAD_ALL_PRODUCTS_FAIL: {
return { loader: false, error: payload };
}
default:
return state;
}
};
thunk.js
import axios from 'axios';
import { mockData } from '../MockData';
import {
loadAllProductFailed,
loadAllProductRequest,
loadAllProductSuccess,
LOAD_PRODUCT_FAIL,
LOAD_PRODUCT_REQUEST,
LOAD_PRODUCT_SUCCESS,
} from './actions';
export const loadInitialProducts = () => async (dispatch) => {
try {
dispatch(loadAllProductRequest());
//this is where the issues is
const response = await axios.get('http://localhost:8080/v1/product/all');
const payload = await response.data;
console.log(payload);
dispatch(loadAllProductSuccess(payload));
} catch (error) {
dispatch(
loadAllProductFailed(
error.response && error.response.data.message
? error.response.data.message
: error.message
)
);
}
};
export const loadProductDetails = (id) => async (dispatch) => {
try {
dispatch({ type: LOAD_PRODUCT_REQUEST });
//do a axios api call for product api
dispatch({
type: LOAD_PRODUCT_SUCCESS,
payload: mockData.find(({ productId }) => productId == id),
});
} catch (error) {
dispatch({
type: LOAD_PRODUCT_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
export const LOAD_ALL_PRODUCTS_REQUEST = 'LOAD_PRODUCTS_REQUEST';
export const loadAllProductRequest = () => ({
type: LOAD_ALL_PRODUCTS_REQUEST,
});
export const LOAD_ALL_PRODUCTS_SUCCESS = 'LOAD_ALL_PRODUCTS_SUCCESS';
export const loadAllProductSuccess = (payload) => ({
type: LOAD_ALL_PRODUCTS_SUCCESS,
payload: payload,
});
export const LOAD_ALL_PRODUCTS_FAIL = 'LOAD_ALL_PRODUCTS_FAIL';
export const loadAllProductFailed = (error) => ({
type: LOAD_ALL_PRODUCTS_FAIL,
payload: error,
});
export const LOAD_PRODUCT_REQUEST = 'LOAD_PRODUCT_REQUEST';
export const loadProductRequest = () => ({
type: LOAD_ALL_PRODUCTS_FAIL,
});
export const LOAD_PRODUCT_SUCCESS = 'LOAD_PRODUCT_SUCCESS';
export const loadProductSuccess = (payload) => ({
type: LOAD_ALL_PRODUCTS_FAIL,
payload: payload,
});
export const LOAD_PRODUCT_FAIL = 'LOAD_PRODUCT_FAIL';
export const loadProductFailed = (error) => ({
type: LOAD_ALL_PRODUCTS_FAIL,
payload: error,
});
Home.js
import React, { useState, useEffect } from 'react';
import { conwayAPI } from '../ConwayAPI';
import { Container, Col, Row } from 'react-bootstrap';
import Product from './Product';
import { useDispatch, useSelector } from 'react-redux';
import _ from 'lodash';
import { loadInitialProducts } from '../app/thunk';
const Home = () => {
//local state maintained only for this component
const [filterProducts, setFilterProducts] = useState([]);
const dispatch = useDispatch();
const productList = useSelector((state) => state.productData);
const { loader, error, products } = productList;
useEffect(() => {
dispatch(loadInitialProducts());
}, [dispatch, products]);
const doSearch = (text) => {
_.isEmpty(text)
? setFilterProducts(products)
: setFilterProducts(
filterProducts.filter((product) =>
product.productName.toLowerCase().includes(text.toLowerCase())
)
);
};
return (
<Container fluid>
<Row md={7} lg={5} className='justify-content-md-center'>
{filterProducts.length &&
filterProducts.map((datam, key) => {
return (
<Col key={key}>
<Product product={datam} key={key} />
</Col>
);
})}
</Row>
</Container>
);
};
export default Home;
When I click on a Nav panel the Home.js gets called and the error starts. What can I do differently to eliminate this error?

Call a redux action in a function helper

I'm trying to create an alert component, however for this I need to add an item (from anywhere) to the list of alerts in the state.
I have this code:
alertReducer.js:
import { SET_ALERT, GET_ALERTS, SET_ALERT_SHOWED } from "../actions/types";
const initialState = {
alerts: [
{
id: 0,
title: "teste",
message: "teste",
isShowed: false,
type: "success"
}
]
};
export default function(state = initialState, action) {
switch (action.type) {
case SET_ALERT:
return { ...state, alert: action.payload };
case SET_ALERT_SHOWED:
return {
...state,
alert: state.alerts.map(a =>
a.id === a.payload.id ? (a = action.payload) : a
)
};
case GET_ALERTS:
return { ...state };
default:
return state;
}
}
alertActions.js
import { SET_ALERT, GET_ALERTS, SET_ALERT_SHOWED } from "./types";
import axios from "axios";
export const getAlerts = () => dispatch => {
dispatch({
type: GET_ALERTS,
payload: null
});
};
export const setAlertShowed = alert => dispatch => {
dispatch({
type: SET_ALERT_SHOWED,
payload: null
});
};
export const setAlert = alert => dispatch => {
console.log("set alert:");
this.setState(state => {
state.alert.alerts.push(alert);
return null;
});
dispatch({
type: SET_ALERT,
payload: null
});
};
alerts.js (component)
import React from "react";
import { Link } from "react-router-dom";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import {
Panel,
PanelHeader,
PanelBody
} from "./../../components/panel/panel.jsx";
import SweetAlert from "react-bootstrap-sweetalert";
import ReactNotification from "react-notifications-component";
import "react-notifications-component/dist/theme.css";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { getAlerts, setAlertShowed } from "../../actions/alertActions";
class Alerts extends React.Component {
constructor(props) {
super(props);
this.addNotification = this.addNotification.bind(this);
this.notificationDOMRef = React.createRef();
}
componentWillReceiveProps(nextProps) {
console.log("atualizou alertas");
console.log(this.props);
console.log(nextProps);
}
componentDidMount() {
this.props.getAlerts();
this.showAlerts();
}
showAlerts() {
const { alerts } = this.props;
alerts
.filter(a => !a.isShowed)
.map((a, i) => {
this.addNotification.call(this, a);
a.isShowed = true;
setAlertShowed(a);
});
}
addNotification(alert) {
this.notificationDOMRef.current.addNotification({
title: alert.title,
message: alert.message,
type: alert.type,
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: { duration: 2000 },
dismissable: { click: true }
});
}
render() {
const { alerts } = this.props;
return <ReactNotification ref={this.notificationDOMRef} />;
}
}
Alerts.propTypes = {
alerts: PropTypes.array.isRequired,
getAlerts: PropTypes.func.isRequired,
setAlertShowed: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
alerts: state.alert.alerts
});
export default connect(
mapStateToProps,
{ getAlerts, setAlertShowed }
)(Alerts);
So I have this helper I'm trying to do, it would serve so that from anywhere in the application I can trigger addAlert and generate a new alert, but I have no idea how to call the setAlert function inside the alertActions.js, what I was able to do is call the SET_ALERT through the store.dispatch, but apparently this is not triggering the setAlert or I am doing something wrong
import uuid from "uuid";
import { createStore } from "redux";
import { setAlert } from "../actions/alertActions";
import { SET_ALERT } from "../actions/types";
import alertReducer from "../reducers/alertReducer";
export function addAlert(state, title, message, type = "success") {
// const store = createStore(alertReducer);
// const state = store.getState();
const newalert = {
id: uuid.v4(),
title,
message,
isShowed: false,
type: type
};
console.log("state");
console.log(state);
// this.setState(state => {
// state.alert.alerts.push(alert);
// return null;
// });
// store.dispatch({
// type: SET_ALERT,
// payload: newalert
// });
// store.dispatch(setAlert(newalert));
// store.dispatch(SET_ALERT);
// this.setState(prevState => ({
// alert.alerts: [...prevState.alert.alerts, newalert]
// }))
}
PS. My react knowledge is very low yet and English it's not my primary language, if I don't make myself clear please ask anything.
Thank you.
Do like this:
// Create alert which you want to show
const alerts = [
{
id: 0,
title: "teste",
message: "teste",
isShowed: false,
type: "success"
}];
componentDidMount() {
this.props.getAlerts();
this.showAlerts();
// this will call alerts action
this.props.callAlert(alerts );
}
const mapDispatchToProps = dispatch=> ({
callAlert: (alert) => dispatch(setAlert(alert)),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
{ getAlerts, setAlertShowed }
)(Alerts);
Finally! I created the store by adding compose and applyMiddleware, I still have to study how this works best but it worked.
The helper code to add alert looks like this:
import uuid from "uuid";
import { createStore, dispatch, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { setAlert } from "../actions/alertActions";
import alertReducer from "../reducers/alertReducer";
export function addAlert(title, message, type = "success") {
const store = createStore(alertReducer, compose(applyMiddleware(thunk)));
const newalert = {
id: uuid.v4(),
title,
message,
isShowed: false,
type: type
};
store.dispatch(setAlert(newalert));
}

Redux-Saga Getting undefined on componentDidMount()

I'm building a React Component which basically needs to get data from database and load into the Table
AdminActions\index.js // My Action
import {
SHOW_MESSAGE,
HIDE_MESSAGE,
GET_NON_ACTIVE_USERS,
GET_NON_ACTIVE_USERS_SUCCESS,
} from "constants/ActionTypes";
export const getNonActiveUsers = (options) => {
return {
type: GET_NON_ACTIVE_USERS,
payload: options
};
};
export const getNonActiveUsersSuccess = (users) => {
return {
type: GET_NON_ACTIVE_USERS_SUCCESS,
payload : users
};
};
export const showSuccessMessage = (message) => {
return {
type: SHOW_MESSAGE,
payload: message
};
};
export const hideMessage = () => {
return {
type: HIDE_MESSAGE,
};
};
AdminReducers\index.js // My Reducer
import {
SHOW_MESSAGE,
HIDE_MESSAGE,
GET_NON_ACTIVE_USERS_SUCCESS,
} from "constants/ActionTypes";
const INIT_STATE = {
alertMessage: '',
showMessage: false,
};
export default (state = INIT_STATE, action) => {
switch (action.type) {
case GET_NON_ACTIVE_USERS_SUCCESS:{
return {
...state,
users: action.payload,
}
}
case SHOW_MESSAGE: {
return {
...state,
alertMessage: action.payload,
showMessage: true,
loader: false
}
}
case HIDE_MESSAGE: {
return {
...state,
alertMessage: '',
showMessage: false,
}
}
default:
return state;
} }
AdminSagas\index.js // My Saga
import {all, call, fork, put, takeEvery} from "redux-saga/effects";
import {
GET_NON_ACTIVE_USERS,
} from "constants/ActionTypes";
import {showSuccessMessage,getNonActiveUsersSuccess } from "../../actions/AdminActions";
import{ base_url } from "../../../util/config";
const getNonActiveUsersRequest = async ({page,limit}) => {
return await fetch(base_url+"/api/admin/getNonActiveUsers",
{
method: 'get',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Authorization' : "Bearer " + JSON.parse(localStorage.getItem('user')).token
}
})
.then(res => res.json())
.then(data => {
return data;
})
.catch(error => {
return error;
});
};
function* getNonActiveUsers(payload) {
try {
const response = yield call(getNonActiveUsersRequest,payload);
if (response.message) {
yield put(showSuccessMessage(response.message));
} else {
yield put(getNonActiveUsersSuccess(response));
}
} catch (error) {
yield put(showSuccessMessage(error));
}
};
export function* getNonActiveUsersCatcher() {
yield takeEvery(GET_NON_ACTIVE_USERS, getNonActiveUsers)
}
export default function* rootSaga() {
yield all([fork(getNonActiveUsersCatcher)
]);
}
My Component
import React, {Component} from "react";
import {connect} from "react-redux";
import {Table} from "antd";
import {getNonActiveUsers, hideMessage} from "appRedux/actions/AdminActions/";
const columns = [{
title: 'Name & Surname',
dataIndex: 'fullName',
}, {
title: 'Email',
dataIndex: 'email',
}, {
title: 'Phone',
dataIndex: 'phone',
},{
title: 'Activation Status',
dataIndex: 'user_info.activationStatus',
}];
class ActivateInvestors extends Component {
state = {
data: [],
pagination: {},
loading: false
};
componentDidMount() {
this.props.getNonActiveUsers();
}
render() {
console.log(this.props.users);
return (
<Table
columns={columns}
rowKey={record => record._id}
dataSource={this.props.users}
pagination={this.state.pagination}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
}
}
const mapStateToProps = ({admin}) => {
const {loader,alertMessage, showMessage, users} = admin;
return {loader,alertMessage, showMessage, users}
};
export default connect(mapStateToProps, {
getNonActiveUsers,
hideMessage,
})(ActivateInvestors);
So the first console.log output is undefined and I dont know how to solve the problem professionally. I can handle with if checks but I dont want to do that.
Output :
I can get the data successfully but I dont know where to assign the values or call the function.
You have to use if checks, coz first time when the render is called your user prop is undefined. After your reducers assigned the value it will get re-render. By the time you'll be seeing the data on the log.
Something like this am using lodash here:
if (!_.isEmpty(this.props.users)) {
return (
<Table
columns={columns}
rowKey={record => record._id}
dataSource={this.props.users}
pagination={this.state.pagination}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
} else {
return <p>Loading...</p>;
}
You first console.log is "undefined", because by the time the render function is executed for the first time, you are still fetching the data from the endpoint. When you finally retrieve the data, you see a re-render of the component, and then you get the values shown in the console.log. You need to explain better what you want to achieve so we can help you better.

Store values not changing after dispatch

I am new to react redux and I am facing an issue with store note changing it values. I read a manual and then implemented the reducer and action. Implemented ACTION AND Reducer but state is not getting updated. Any help would be appreciated.
See below for my component file
import React from 'react'
import { Grid } from 'semantic-ui-react'
import uuid from 'uuid'
import axios from 'axios'
import _ from 'lodash'
import PropTypes from "prop-types";
import EditableTimerList from './EditableTimerList'
import ToggleableTimerForm from './ToggleableTimerForm'
import { newTimer } from './helpers'
import { updateAll, createUrlWithParams, updateTrackOnStartOrStop } from './services';
import Filters from './Filters';
import { connect } from "react-redux";
import {getDataForTimerDashBoard} from '../actions/timerAction';
var querystring = require('querystring');
class TimerDashboard extends React.Component {
constructor () {
super()
this.queryJson = { runningSince: '', title: ''};
this.state = {
timers: [
{
title: 'The default one',
description: 'This is a description',
elapsed: null,
runningSince: null,
id: uuid.v4(),
updateDate: new Date().toISOString()
}
]
}
};
componentDidMount() {
this.getData(this);
console.log(this.props.timers);
}
getData(that) {
this.props.getDataForTimerDashBoard(this.state.timers);
}
updateTimer (attrs) {
}
createTimer (timer) {
}
deleteTimer (timerId) { }
startTimer (timerId) {
}
stopTimer (timerId) {
}
onQueryChange(query) {
}
saveDataToState(that, data) {
}
render () {
const onQueryChange = _.debounce((query)=>{this.onQueryChange(query)}, 400);
return (
<div className="container">
<div className="row">
<EditableTimerList
timers={this.state.timers}
onFormSubmit={attrs => this.updateTimer(attrs)}
onTrashClick={timerId => this.deleteTimer(timerId)}
onStartClick={timerId => this.startTimer(timerId)}
onStopClick={timerId => this.stopTimer(timerId)}
/>
<ToggleableTimerForm
onFormSubmit={timer => this.createTimer(timer)}
/>
<Filters
onTextChange={(query)=>{onQueryChange(query)}}
onCheckboxChange={(query)=>{this.onQueryChange(query)}}
/>
</div>
</div>
)
}
}
TimerDashboard.propTypes = {
getDataForTimerDashBoard: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired,
timers: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors,
timers: state.timers
});
export default connect(
mapStateToProps,
{getDataForTimerDashBoard}
)(TimerDashboard);
Store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
//window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
See below fro my type file
type.js
export const GET_ERRORS = "GET_ERRORS";
export const USER_LOADING = "USER_LOADING";
export const SET_CURRENT_USER = "SET_CURRENT_USER";
export const LOAD_TIMER_DATA = "LOAD_TIMER_DATA";
reducer.js
import {LOAD_TIMER_DATA} from "../actions/types";
import uuid from 'uuid';
const isEmpty = require("is-empty");
const initialState = {
isAuthenticated: false,
user: {},
loading: false,
timers: {}
};
export default function (state = initialState, action) {
switch (action.type) {
case LOAD_TIMER_DATA:
console.log(action)
return {
...state,
isAuthenticated: !isEmpty(action.payload.usertoken),
user: action.payload.usertoken,
timers: action.payload.timers
};
default:
return state;
}
}
Timeraction
import axios from "axios";
import jwt_decode from "jwt-decode";
import {GET_ERRORS, LOAD_TIMER_DATA} from "./types";
var querystring = require('querystring');
// Register User
export const getDataForTimerDashBoard = (timerData) => async dispatch => {
const token = localStorage.getItem("jwtToken");
const decoded = jwt_decode(token);
//If no data remains in db, put the two dummy data of state into the db
await axios.get('/getAll').then(function (response) {
let savedTimers = [];
if (response.data.length === 0) {
timerData.timers.forEach((timer) => {
axios.post('/insert',
querystring.stringify(timer), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(function (response) {
timer.id = response.data.id
savedTimers.push(timer);
dispatch({
type: LOAD_TIMER_DATA,
payload: savedTimers
})
}).catch(err => {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
});
});
} else {
alert(response.data);
const payload ={};
payload.timers = response.data;
payload.usertoken = decoded;
dispatch({
type: LOAD_TIMER_DATA,
payload: payload,
})
}
});
};
I think there is an issue in the code, while dispatching in payload you are pushing only SavedTimers but in reducer, you are trying to access userToken
savedTimers.push(timer);
dispatch({
type: LOAD_TIMER_DATA,
payload: savedTimers
})
Please add userToken also to your payload.
EDIT
import axios from "axios";
import jwt_decode from "jwt-decode";
import {GET_ERRORS, LOAD_TIMER_DATA} from "./types";
var querystring = require('querystring');
// Register User
export const getDataForTimerDashBoard = (timerData) => async dispatch => {
const token = localStorage.getItem("jwtToken");
const decoded = jwt_decode(token);
const payload ={};
payload.usertoken = decoded;
//If no data remains in db, put the two dummy data of state into the db
await axios.get('/getAll').then(function (response) {
let savedTimers = [];
if (response.data.length === 0) {
timerData.timers.forEach((timer) => {
axios.post('/insert',
querystring.stringify(timer), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(function (response) {
timer.id = response.data.id
savedTimers.push(timer);
payload.timers = savedTimers;
dispatch({
type: LOAD_TIMER_DATA,
payload: payload,
})
}).catch(err => {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
});
});
} else {
payload.timers = response.data;
dispatch({
type: LOAD_TIMER_DATA,
payload: payload,
})
}
});
};

Resources