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.
Related
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
I'm working on a MERN Stack. The database is posting to the route correctly, but the reducer is not receiving the action when trying to read all the database entries. It's possible that the action readAllEmployment() is not being hit by the front end correctly, but the information does render in PostMan.
index.js
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import { Carousel } from '../../components'
import { readAllEmployment } from '../../actions'
import './_resumeRender.scss'
const ResumeRender = () => {
useEffect(() => {
console.log('Hit Use Effect')
readAllEmployment()
}, [])
return <></>
}
const mapStateToProps = (state) => ({
resumeEmploymentReducer: state.resumeEmploymentReducer,
})
export default connect(mapStateToProps)(ResumeRender)
route.js
// load Model
const employmentModel = require('../models/employmentModel')
// #Route GET api/employment/
// #Desc Read All Employment
// #Action readAllEmployment()
// #Access Private
router.get('/', async (req, res) => {
console.log('readAllEmployment Route')
try {
const employment = await employmentModel.find().sort('endDate')
if (employment.length <= 0) {
return res.status(400).json({
errors: [{ msg: 'No employment was found' }],
})
}
return res.json(employment)
} catch (err) {
console.error(err.message)
return res.status(500).send('Server Error')
}
})
reducer.js
import {
GET_ALL_EMPLOYMENT,
GET_ONE_EMPLOYMENT,
DELETE_EMPLOYMENT,
RESET_EMPLOYMENT,
EMPLOYMENT_LOADING,
EMPLOYMENT_FAIL,
EMPLOYMENT_SUCCESS,
} from '../actions'
const resumeEmploymentReducer = (
state = {
allEmployment: [], // Pulls in all employment
employment: null, // Pulls in Specific employment
loading: false, // Has everything need been loaded
success: {},
error: {},
},
action,
) => {
const { type, payload } = action
switch (type) {
case GET_ALL_EMPLOYMENT:
console.log('GET_ALL_EMPLOYMENT Reducer')
return {
...state,
allEmployment: payload,
loading: false,
}
case GET_ONE_EMPLOYMENT:
return {
...state,
employment: payload,
loading: false,
}
case DELETE_EMPLOYMENT:
return {
...state,
allEmployment: payload,
loading: false,
}
case RESET_EMPLOYMENT:
return {
...state,
employment: null,
loading: false,
}
case EMPLOYMENT_LOADING:
return {
...state,
loading: true,
employment: null,
error: {},
}
case EMPLOYMENT_FAIL:
return {
...state,
error: payload,
allEmployment: [],
employment: null,
loading: false,
}
case EMPLOYMENT_SUCCESS:
return {
...state,
success: payload,
}
default:
return state
}
}
export default resumeEmploymentReducer
action.js
export const GET_ALL_EMPLOYMENT = 'GET_ALL_EMPLOYMENT'
export const GET_ONE_EMPLOYMENT = 'GET_ONE_EMPLOYMENT'
export const DELETE_EMPLOYMENT = 'ELETE_EMPLOYMENT'
export const RESET_EMPLOYMENT = 'RESET_EMPLOYMENT'
export const EMPLOYMENT_LOADING = 'EMPLOYMENT_LOADING '
export const EMPLOYMENT_FAIL = 'EMPLOYMENT_FAIL'
export const EMPLOYMENT_SUCCESS = 'EMPLOYMENT_SUCCESS'
// #Route GET api/employment
// #Desc Read All Employment
// #Action readAllEmployment()
// #Access Private
export const readAllEmployment = () => async (dispatch) => {
console.log('readAllEmployment Action')
try {
const res = await axios.get('/api/employment/')
dispatch({
type: GET_ALL_EMPLOYMENT,
payload: res.data,
})
} catch (err) {
if (err.response.data.errors) {
dispatch({
payload: { msg: err.response.statusText, status: err.response.status },
})
}
dispatch({
type: EMPLOYMENT_FAIL,
payload: { msg: err.response.statusText, status: err.response.status },
})
}
}
Redux DevTools
resumeEmploymenrReducer
allEmployment: []
employment: null
loading: false
success: { }
error: { }
console
Hit Use Effect
terminal
[1] Compiled successfully!
[0] Server is running on port 6060
[0] Database connected!
[0] readAllEmployment Route
PostMan
GET: http://localhost:6060/api/employment/
BODY RETURNS
[
{
"_id": "614b517cbc3fdc6d0d82ec4d",
"title": "Job Title",
"employmentType": "Full-Time",
"company": "Compnay Name",
"locationCity": "City",
"locationState": "State",
"startDate": "01-01-2021",
"endDate": "01-01-2021",
"description": "Description",
"__v": 0
}
]
I think you might need to utilize useDispatch from react-redux library.
import { useDispatch } from 'react-redux';
import { readAllEmployment } from '../../actions';
const ResumeRender = () => {
const dispatch = useDispatch()
useEffect(() => {
console.log('Hit Use Effect')
dispatch(readAllEmployment())
}, [])
return <></>
}
export default ResumeRender
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');
I've been debugging why my state hasn't been changing and noticed this being logged in my reducer:
{ type: '##redux/INITi.8.g.w.a.m' }
This is the store which includes state, action types, reducer, actions:
/* initial state */
import axios from 'axios';
export var usersStartState = {
accountNotVerified: null,
isLoggedIn: false,
error: true,
userAvatar: 'uploads/avatar/placeholder.jpg'
};
/* action types */
export const actionTypes = {
RESET_USER_ACCOUNT_IS_VERIFIED: 'RESET_USER_ACCOUNT_IS_VERIFIED',
USER_ACCOUNT_IS_VERIFIED: 'USER_ACCOUNT_IS_VERIFIED',
USER_ACCOUNT_NOT_VERIFIED: 'USER_ACCOUNT_NOT_VERIFIED',
IS_LOGGED_IN: 'IS_LOGGED_IN',
IS_LOGGED_OUT: 'IS_LOGGED_OUT',
LOAD_USER_AVATAR: 'LOAD_USER_AVATAR',
ERROR_LOADING: 'ERROR_LOADING' // LOAD_MULTER_IMAGE: "LOAD_MULTER_IMAGE"
};
/* reducer(s) */
export default function users(state = usersStartState, action) {
console.log('In users reducer! ', action);
switch (action.type) {
case actionTypes.RESET_USER_ACCOUNT_IS_VERIFIED:
return Object.assign({}, state, { accountNotVerified: null });
case actionTypes.USER_ACCOUNT_IS_VERIFIED:
return Object.assign({}, state, { accountNotVerified: false });
case actionTypes.USER_ACCOUNT_NOT_VERIFIED:
return Object.assign({}, state, { accountNotVerified: true });
case actionTypes.IS_LOGGED_IN:
return Object.assign({}, state, { isLoggedIn: true });
case actionTypes.IS_LOGGED_OUT:
return Object.assign({}, state, { isLoggedIn: false });
case actionTypes.LOAD_USER_AVATAR:
return { ...state, userAvatar: action.data };
case actionTypes.ERROR_LOADING:
return Object.assign({}, state, { error: true });
default:
return state;
}
}
/* actions */
export const resetUserAcoountVerified = () => {
return { type: actionTypes.RESET_USER_ACCOUNT_IS_VERIFIED };
};
export const userHasBeenVerified = () => {
return { type: actionTypes.USER_ACCOUNT_IS_VERIFIED };
};
export const userHasNotBeenVerified = () => {
return { type: actionTypes.USER_ACCOUNT_NOT_VERIFIED };
};
export const logInUser = () => {
return { type: actionTypes.IS_LOGGED_IN };
};
export const logOutUser = () => {
axios
.get('/users/logout')
.then(response => {
if (response.status === 200) {
console.log('You have been logged out!');
}
})
.catch(function(error) {
if (error.response.status === 500) {
console.log('An error has occured');
}
});
return { type: actionTypes.IS_LOGGED_OUT };
};
export const loadAvatar = data => {
console.log('in load avatar ', data);
return { type: actionTypes.LOAD_USER_AVATAR, data: data };
};
export const errorLoading = () => {
return { type: actionTypes.ERROR_LOADING };
};
And this is my component:
import { useState } from 'react';
import { Card, Icon, Image, Segment, Form } from 'semantic-ui-react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { loadAvatar } from '../../store/reducers/users/index';
import axios from 'axios';
function ImageUploader({ userAvatar }) {
var [localUserAvatar, setLocalUserAvatar] = useState(userAvatar);
function fileUploader(e) {
e.persist();
var imageFormObj = new FormData();
imageFormObj.append('imageName', 'multer-image-' + Date.now());
imageFormObj.append('imageData', e.target.files[0]);
loadAvatar('foo');
axios({
method: 'post',
url: `/users/uploadmulter`,
data: imageFormObj,
config: { headers: { 'Content-Type': 'multipart/form-data' } }
})
.then(data => {
if (data.status === 200) {
console.log('data ', data);
console.log('path typeof ', typeof data.data.path);
loadAvatar('foo');
setLocalUserAvatar('../../' + data.data.path);
}
})
.catch(err => {
alert('Error while uploading image using multer');
});
}
Here are
console.log('userAvatar in imageUploader ', userAvatar);
console.log('Date.now() line 44 in imageUploader ', Date.now());
console.log('localUserAvatar in imageUploader ', localUserAvatar);
console.log('Date.now() line 46 in imageUploader ', Date.now());
console.log("loadAvatar('barbar') ", loadAvatar('barbar'));
return (
<>
<Segment>
<Card fluid>
<Image src={localUserAvatar} alt="upload-image" />
<Segment>
<Form encType="multipart/form-data">
<Form.Field>
<input
placeholder="Name of image"
className="process__upload-btn"
type="file"
content="Edit your Avatar!"
onChange={e => fileUploader(e)}
/>
</Form.Field>
</Form>
</Segment>
<Card.Content>
<Card.Header>Charly</Card.Header>
<Card.Meta>
<span className="date">Joined in 2015</span>
</Card.Meta>
<Card.Description>Charly</Card.Description>
</Card.Content>
<Card.Content extra>
<a>
<Icon name="user" />
22 Friends
</a>
</Card.Content>
</Card>
</Segment>
</>
);
}
function mapStateToProps(state) {
const { users } = state;
const { userAvatar } = users;
return { userAvatar };
}
const mapDispatchToProps = dispatch => bindActionCreators({ loadAvatar }, dispatch);
export default connect(
mapStateToProps,
mapDispatchToProps
)(ImageUploader);
From the logs you can see loadAvatar the dispatcher, gets fired in the component and in the store...
But the state in the store never changes....
Also other states do change correctly...Like for example I have a Modal and that updates nicely.
Any help would be appreciated as what { type: '##redux/INITi.8.g.w.a.m' } and why my state is not updating?
Redux dispatches that action as an internal initialization step:
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT })
It's specifically so that your reducers will see the action, not recognize the action type, and return their default state, thus defining the initial overall app state contents.
I'm having a problem here, I have been doing redux for about 2 weeks now.
I'm trying to create a loader so I am trying to get the isFetching state. Using thunk, i'm doing an ajax fetch, and dispatching the loading state.
The dispatch was called, because I can see in my console.
before component will mount, its suppose to call FETCH_PROFILE, and isFetching set to true, but when i console.log(this.props.profile.isFetching), it's returning false.
Same for FETCH_PROFILE_SUCCESS, it doesn't update this.props.profile. (Or because It's not rerendering...so I can't see it)
I've been working on this simple thing for hours and I have no idea why it doesn't update...... I am sure I made some mistake somewhere but no idea what.
export const FETCH_PROFILE = 'FETCH_PROFILE';
export const FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS';
export const FETCH_PROFILE_FAIL = 'FETCH_PROFILE_FAIL';
export function getUserProfile() {
return (dispatch) => {
dispatch(getUserProfileStart());
const config2 = {
method: 'GET',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
credentials: 'include',
body: ``,
};
fetch('http://api.example.com/profile/',config2)
.then((resp) => resp.json())
.then(function(data) {
dispatch(getUserProfileSuccess(data));
return 0;
}).catch(function(error){
return dispatch({type: FETCH_PROFILE_FAIL});
})
}
}
function getUserProfileSuccess(data) {
return {
type: FETCH_PROFILE_SUCCESS,
isFetching: false,
payload: data
}
}
function getUserProfileStart() {
return {
type: FETCH_PROFILE,
isFetching: true
}
}
my reducer
import {
FETCH_PROFILE,
FETCH_PROFILE_SUCCESS,
FETCH_PROFILE_FAIL
} from '../actions/profile';
export default function userProfile(state={isFetching: false}, action) {
switch(action.type) {
case FETCH_PROFILE:
return {...state, isFetching: true}
case FETCH_PROFILE_SUCCESS:
return {...state, isFetching: false, data: action.payload}
case FETCH_PROFILE_FAIL:
return { ...state, isFetching: false };
default:
return state
}
}
My Component.
import React from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import {connect } from 'react-redux';
import * as profileActions from '../../actions/profile';
import {bindActionCreators} from 'redux';
class ProfilePage extends React.Component {
constructor(props) {
super(props);
this.getUserProfile = this.getUserProfile.bind(this);
}
componentWillMount() {
this.props.actions.getUserProfile();
}
render() {
console.log('Checking isFetching State', this.props.profile.isFetching);
return (
<div>
some text here.
</div>
);
}
}
function mapStateToProps(state) {
console.log('Mapping Stat', state.profile);
return {
profile: state.userProfile
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(profileActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(s)(ProfilePage));
my combine reducers...
import userProfile from './profile';
//some other imports...
export default combineReducers({
userProfile,
//other reducers that works...
});
Try this:
At index while creating store
export const store = createStore(
combineReducer,
applyMiddleware(thunk) // choose you middleware....
//initial state as per need
);
At reducer:
import {
FETCH_PROFILE,
FETCH_PROFILE_SUCCESS,
FETCH_PROFILE_FAIL
} from '../actions/profile';
export default function userProfile(state= {
initialized: true,
init:false,
success:false,
fail:false,
}, action) {
switch(action.type) {
case FETCH_PROFILE:{
const message = action.message;
return Object.assign({}, state, {
init:true,
success:false,
fail:false,
data:message,
})
}
}
case FETCH_PROFILE_SUCCESS:{
const data = action.data;
return Object.assign({}, state, {
init:false,
success:true,
fail:false,
data:data,
})
}
case FETCH_PROFILE_FAIL:{
const err = action.err;
return Object.assign({}, state, {
init:false,
success:false,
fail:true,
data:err,
})
}
default:
return state
}
}
At Component:
import React from 'react';
//use can use this if required.
//import withStyles from 'isomorphic-style-loader/lib/withStyles';
import {connect } from 'react-redux';
import { profileActions} from '../../actions/profile';
//import {bindActionCreators} from 'redux';
class ProfilePage extends React.Component {
constructor(props) {
super(props);
this.state{
success:false;
}
}
componentWillMount() {
this.props.getUserProfile();
}
componentWillReciveProps(nextprop){
if(nextprop.success===true){
this.setState({success==true});
}
}
render() {
return (
{(this.state.success)?<div>this.props.profile.data.yourdata</div>:<div>Loading....</div>}
);
}
}
function mapStateToProps(state) {
return {
profile: state.userProfile
};
}
export default connect(mapStateToProps,{profileActions
})(ProfilePage);
At action:
export const FETCH_PROFILE = 'FETCH_PROFILE';
export const FETCH_PROFILE_SUCCESS = 'FETCH_PROFILE_SUCCESS';
export const FETCH_PROFILE_FAIL = 'FETCH_PROFILE_FAIL';
export function getUserProfile() {
return (dispatch) => {
dispatch(getUserProfileStart(const message:"fetch start"));
const config2 = {
method: 'GET',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
credentials: 'include',
body: ``,
};
fetch('http://api.example.com/profile/',config2)
.then((resp) => resp.json())
.then(function(data) {
dispatch(getUserProfileSuccess(data));
return 0;
}).catch(function(error){
return dispatch(getUserProfileError(error));
})
}
}
function getUserProfileSuccess(data) {
return {
type: FETCH_PROFILE_SUCCESS,
data
}
}
function getUserProfileStart(message) {
return {
type: FETCH_PROFILE,
message
}
}
function getUserProfileError(err) {
return {
type: FETCH_PROFILE,
err
}
}