Cannot read property 'data' of undefined in ReactJs and SwaggerUI - javascript

I am working with ReactJs and Fetch API from Swagger UI. I code for Room management, this is my code for that
In actions.js file
// Room type action
export const actFetchRoomTypesRequest = () => {
return (dispatch) => {
return callApi('admin/host-room-types', 'GET', null).then((res) => {
dispatch(actFetchRoomTypes(res.data));
});
};
};
export const actFetchRoomTypes = (roomTypes) => {
return {
type: Types.FETCH_ROOMTYPES,
roomTypes,
};
};
export const actDeleteRoomTypeRequest = (id) => {
return (dispatch) => {
return callApi(`admin/host-room-types/${id}`, 'DELETE', null).then((res) => {
dispatch(actFetchRoomTypesRequest());
});
};
};
export const actAddRoomTypeRequest = (roomType) => {
return (dispatch) => {
return callApi(`admin/host-room-types`, 'POST', roomType).then((res) => {
return callApi(`admin/host-room-types`).then((ress) => {
dispatch(actFetchRoomTypes(ress.data));
});
});
};
};
export const actAddRoomType = (roomType) => {
return {
type: Types.ADD_ROOMTYPE,
roomType,
};
};
export const actGetRoomTypeRequest = (id) => {
return (dispatch) => {
return callApi(`admin/host-room-types/${id}`, 'GET', null).then((res) => {
dispatch(actGetRoomType(res.data));
});
};
};
export const actGetRoomType = (roomType) => {
return {
type: Types.EDIT_ROOMTYPE,
roomType,
};
};
export const actUpdateRoomTypeRequest = (roomType) => {
return (dispatch) => {
return callApi(`admin/host-room-types/${roomType.id}`, 'PUT', roomType).then((res) => {
return callApi(`admin/host-room-types`).then((ress) => {
dispatch(actFetchRoomTypes(ress.data));
});
});
};
};
export const actUpdateRoomType = (roomType) => {
return {
type: Types.UPDATE_ROOMTYPE,
roomType,
};
};
In RoomTypeItem.js which the place I show all action for that
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class RoomTypeItem extends Component {
constructor(props) {
super(props);
console.log('constructor');
}
onDelete = (id) => {
console.log(id);
if (window.confirm('ban muon xoa?')) {
this.props.onDelete(id);
}
};
onSelectRoomType = (id) => {
console.log('onSelect' + id);
this.props.onSelect(id);
};
render() {
var { roomType, index } = this.props;
console.log('render' + roomType.id + this.props.checked);
return (
<tr>
<td>
<input
type="checkbox"
className="delid[]"
checked={this.props.checked}
onChange={() => this.onSelectRoomType(roomType.id)}
/>
</td>
<td>{index + 1}</td>
<td>{roomType.name}</td>
<td>{roomType.description}</td>
<td>
<Link to={`/roomType/${roomType.id}/edit`} className="btn btn-warning mr-10">
Update
</Link>
</td>
</tr>
);
}
}
export default RoomTypeItem;
And in RoomTypeActionPage have code like this
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { actAddRoomTypeRequest, actGetRoomTypeRequest, actUpdateRoomTypeRequest } from './../../actions/index';
import { connect } from 'react-redux';
class RoomTypeActionPage extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
txtName: '',
txtDescription: '',
};
}
componentDidMount() {
var { match } = this.props;
if (match) {
var id = match.params.id;
this.props.onEditRoomType(id);
}
}
componentWillReceiveProps(nextProps) {
if (nextProps && nextProps.itemEditing) {
var { itemEditing } = nextProps;
this.setState({
id: itemEditing.id,
txtName: itemEditing.name,
txtDescription: itemEditing.description,
});
}
}
onChange = (e) => {
var target = e.target;
var name = target.name;
var value = target.type === 'checkbox' ? target.checked : target.value;
this.setState({
[name]: value,
});
};
onSave = (e) => {
e.preventDefault();
var { id, txtName, txtDescription } = this.state;
var { history } = this.props;
var roomType = {
id: id,
name: txtName,
description: txtDescription,
};
if (id) {
//update
this.props.onUpdateRoomType(roomType);
} else {
this.props.onAddRoomType(roomType);
}
history.goBack();
};
render() {
var { txtName, txtDescription } = this.state;
return (
<div className="col-xs-6 col-sm-6 col-md-6 col-lg-6">
<form onSubmit={this.onSave}>
<div className="form-group">
<label>Name:</label>
<input
type="text"
className="form-control"
name="txtName"
value={txtName}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>Description:</label>
<input
type="text"
className="form-control"
name="txtDescription"
value={txtDescription}
onChange={this.onChange}
/>
</div>
<Link to="/roomType-list" className="btn btn-danger mr-10">
Cancel
</Link>
<button type="submit" className="btn btn-primary">
Save
</button>
</form>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
itemEditing: state.itemEditing,
};
};
const mapDispatchToProps = (dispatch, props) => {
return {
onAddRoomType: (roomType) => {
dispatch(actAddRoomTypeRequest(roomType));
},
onEditRoomType: (id) => {
dispatch(actGetRoomTypeRequest(id));
},
onUpdateRoomType: (roomType) => {
dispatch(actUpdateRoomTypeRequest(roomType));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RoomTypeActionPage);
And this is my Reducer
import * as Types from './../constants/ActionTypes';
var initialState = {
loading: false,
data: [],
};
var findIndex = (roomTypes, id) => {
var result = -1;
roomTypes.data.forEach((roomType, index) => {
if (roomType.id === id) {
result = index;
}
});
return result;
};
const roomTypes = (state = initialState, action) => {
var index = -1;
var { id, roomType } = action;
switch (action.type) {
case Types.FETCH_ROOMTYPES:
state = action.roomTypes;
return { ...state };
case Types.DELETE_ROOMTYPE:
index = findIndex(state, id);
state.splice(index, 1);
return { ...state };
case Types.ADD_ROOMTYPE:
state.data.push(action.roomType);
return { ...state };
case Types.UPDATE_ROOMTYPE:
index = findIndex(state, roomType.id);
state[index] = roomType;
return { ...state };
default:
return { ...state };
}
};
export default roomTypes;
I do not know when I run my code it shows me an error like this
I already to check all but I can realize where I code wrong for that. PLease help me, I need you, Thank thank so much
This is my link for swagger UI : here
This is my apiCaller
import axios from 'axios';
import * as Config from './../constants/Config';
export default function callApi(endpoint, method = 'GET', body) {
return axios({
method: method,
url: `${Config.API_URL}/${endpoint}`,
data: body,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization:
'Bearer ' +
'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTU5Njg4MTYxMSwiZXhwIjoxNjEyOTQzNjEwfQ.eXkXWuuIMk94uOtVZQSNysbfJyIQuP5dIFqS06Kx-KsYVCkVEAbU01IhwJpkR4YtgXt8idkN4MM0cT76Xre7Sg',
},
}).catch((err) => {
console.log(err);
});
}

Related

Redux+Reactjs+NodeJS How to get a specific value from the database and display it to the screen by redux?

i am new, and am getting acquainted with i reactjs and nodejs, i am writing a website in which i want to write a function to get the current login information of the user through redux, and then after then assign the obtained user value to react-select, then from react-select, we select that user to perform the assignment of new data to the database from reactjs. However, I have not been able to get the logged in user information through redux. This is my code, anyone have any ideas? Thanks very much
here is my FE(Reactjs code):
here is DoctorManageSchedule.js:
import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import './ManageSchedule.scss';
import Select from 'react-select';
import * as actions from "../../../store/actions";
import { CRUD_ACTIONS, LANGUAGES, dateFormat } from '../../../utils';
import DatePicker from '../../../components/Input/DatePicker';
import moment from 'moment';
import { toast } from "react-toastify";
import _ from 'lodash';
import { saveBulkScheduleDoctor, getScheduleDoctorById } from '../../../services/userService';
import DetailDoctor from './DetailDoctor';
class DoctorManageSchedule extends Component {
constructor(props) {
super(props);
this.state = {
arrDoctor: [],
selectedDoctor: {},
currentDate: '',
rangeTime: [],
minDate: moment().calendar(),
}
}
async componentDidMount() {
this.props.fetchDoctor(this.props.match.params.id);
this.props.fetchAllScheduleTimes();
}
async componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.doctor !== this.props.doctor) {
let dataSelect = this.buildDataInputSelect(this.props.doctor)
this.setState({
arrDoctor: dataSelect
})
}
if (prevProps.allScheduleTime !== this.props.allScheduleTime) {
let data = this.props.allScheduleTime;
if (data && data.length > 0) {
data = data.map(item => ({ ...item, isSelected: false }))
}
this.setState({
rangeTime: data
})
}
}
buildDataInputSelect = (inputData) => {
let result = [];
let { language } = this.props;
if (inputData && inputData.length > 0) {
inputData.map((item, index) => {
let object = {};
let labelEn = `${item.lastName} ${item.firstName}`;
let labelVi = `${item.firstName} ${item.lastName}`;
object.label = language === LANGUAGES.VI ? labelVi : labelEn;
object.value = item.id;
result.push(object)
})
}
return result;
}
handleChangeSelect = async (selectedOption) => {
this.setState({ selectedDoctor: selectedOption });
}
handleOnChangeDatePicker = (date) => {
this.setState({
currentDate: date[0]
})
}
handleClickBtnTime = (time) => {
let { rangeTime } = this.state;
if (rangeTime && rangeTime.length > 0) {
rangeTime = rangeTime.map(item => {
if (item.id === time.id) item.isSelected = !item.isSelected;
return item;
})
this.setState({
rangeTime: rangeTime
})
}
}
handleSaveSchedule = async () => {
let { rangeTime, selectedDoctor, currentDate } = this.state;
let result = [];
if (!currentDate) {
toast.error("Invalid date!");
}
if (selectedDoctor && _.isEmpty(selectedDoctor)) {
toast.error("Invalid selected doctor! ");
console.log('check doctor: ', this.state)
return;
}
let formatedDate = new Date(currentDate).getTime();
if (rangeTime && rangeTime.length > 0) {
let selectedTime = rangeTime.filter(item => item.isSelected === true);
if (selectedTime && selectedTime.length > 0) {
selectedTime.map((schedule, index) => {
let object = {};
object.doctorId = selectedDoctor.value;
object.date = formatedDate;
object.timeType = schedule.keyMap;
result.push(object);
})
} else {
toast.error("Invalid selected time! ");
return;
}
}
let res = await saveBulkScheduleDoctor({
arrSchedule: result,
doctorId: selectedDoctor.value,
formatedDate: formatedDate
})
if (res && res.errCode === 0) {
toast.success("Save Infor succeed!");
} else {
toast.error("error saveBulkScheduleDoctor ");
console.log('error saveBulkScheduleDoctor >>> res: ', res)
}
console.log('bao phuc check result: ', result);
console.log('check res: saveBulkScheduleDoctor : ', res);
}
render() {
let { rangeTime, arrDoctor } = this.state;
console.log("check doctor:", arrDoctor)
let { language } = this.props;
let today = new Date(new Date().setDate(new Date().getDate()));
return (
<div className="manage-schedule-container">
<div className="m-s-title">
<FormattedMessage id="manage-schedule.title"></FormattedMessage>
</div>
<div className="container">
<div className="row">
<div className="col-6 form-group">
<label>
<FormattedMessage id="manage-schedule.choose-doctor" /> </label>
<Select
value={this.state.selectedDoctor}
onChange={this.handleChangeSelect}
options={this.state.listDoctors}
/>
</div>
<div className="col-6 form-group">
<label>
<FormattedMessage id="manage-schedule.choose-date" /> </label>
<DatePicker
value={this.state.currentDate}
className="form-control"
onChange={this.handleOnChangeDatePicker}
minDate={today}
/>
</div>
<div className="col-12 pick-hour-container">
{rangeTime && rangeTime.length > 0 &&
rangeTime.map((item, index) => {
return (
<button className={item.isSelected === true ?
"btn btn-schedule active" : "btn btn-schedule"}
key={index} onClick={() => this.handleClickBtnTime(item)}>
{language === LANGUAGES.VI ? item.valueVi : item.valueEn}
</button>
)
})}
</div>
<div className="col-12">
<button className="btn btn-primary btn-save-schedule"
onClick={() => this.handleSaveSchedule()}>
<FormattedMessage id="manage-schedule.save" />
</button>
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
language: state.app.language,
isLoggedIn: state.user.isLoggedIn,
doctor: state.admin.doctor,
allScheduleTime: state.admin.allScheduleTime,
};
};
const mapDispatchToProps = dispatch => {
return {
fetchDoctor: () => dispatch(actions.fetchDoctorStart()),
fetchAllScheduleTimes: () => dispatch(actions.fetchAllScheduleTimes())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(DoctorManageSchedule);
and here is my actionTypes.js:
const actionTypes = Object.freeze({
FETCH_DOCTOR_SUCCESS: 'FETCH_DOCTOR_SUCCESS',
FETCH_DOCTOR_FAILED: 'FETCH_DOCTOR_FAILED',
})
export default actionTypes;
and here is my adminActions.js:
export const fetchDoctorStart = id => () => {
return async (dispatch, getState) => {
try {
let res = await getScheduleDoctorById(id);
if (res && res.errCode === 0) {
dispatch({
type: actionTypes.FETCH_DOCTOR_SUCCESS,
dataDoctor: res.data
})
} else {
toast.error("Failed to fetch doctor");
dispatch(fetchDoctorFailed());
}
} catch (e) {
toast.error("Failed to fetch doctor");
dispatch(fetchDoctorFailed());
console.log("check fetch doctor failed: ", e);
}
}
};
export const fetchDoctorSuccess = (data) => ({
type: actionTypes.FETCH_DOCTOR_SUCCESS,
doctor: data
})
export const fetchDoctorFailed = () => ({
type: actionTypes.FETCH_DOCTOR_FAILED,
})
here is my adminReducer.js:
case actionTypes.FETCH_DOCTOR_SUCCESS:
state.doctor = action.dataDoctor;
return {
...state,
}
case actionTypes.FETCH_DOCTOR_FAILED:
state.doctor = [];
return {
...state,
}
here is my userService.js:
const getScheduleDoctorById = (inputId) => {
return axios.get(`/api/get-schedule-doctor-by-id?id=${inputId}`)
}
here is my BE(Nodejs code):
here is web.js:
router.get('/api/get-schedule-doctor-by-id', doctorController.getScheduleById);
here is doctorController.js:
let getScheduleById= async (req, res) => {
try {
let infor = await doctorService.getScheduleById(req.query.id);
return res.status(200).json(infor);
} catch (e) {
console.log(e);
return res.status(200).json({
errCode: -1,
errMessage: 'Error from the server'
})
}
}
here is doctorService.js:
let getScheduleById = (inputId) => {
return new Promise(async (resolve, reject) => {
try {
if (!inputId) {
resolve({
errCode: 1,
errMessage: 'Missing required parameter!'
})
} else {
let data = await db.User.findOne({
where: {
id: inputId
},
attributes: {
exclude: ['password']
},
include: [
{ model: db.Allcode, as: 'positionData', attributes: ['valueEn', 'valueVi'] },
{
model: db.Doctor_Infor,
attributes: {
exclude: ['id', 'doctorId']
}
},
],
raw: false,
nest: true
})
if (data && data.image) {
data.image = new Buffer(data.image, 'base64').toString('binary');
}
if (!data) data = {};
resolve({
errCode: 0,
data: data
})
}
} catch (e) {
reject(e);
}
})
}
when i run the app i only get the available time slots from the database, but no info about who is logged in, i checked the network tab, but it seems the api gets the user info via redux do not run. Or does anyone have a way to do it other than using redux, that the user (doctor) can set his own schedule and save it to the database? However, I don't know why, please comment, thanks a lot

Trying to make the todo list update every time a new todo is entered

I am creating a basic todo application in react with flux. I am trying to make it so that every time a new todo is entered in the API, the list is update in real time rather than me having to reload the page the and application making another request. I have tried using componentDidUpdate; however that doesn't seem to work in this case. How should I go about implementing that?
My Todos.js
import React from "react";
import * as TodoActions from "../actions/TodoActions";
import TodoStore from "../stores/TodoStore";
import './Todos.css'
export default class Todos extends React.Component {
constructor() {
super();
this.addItem = this.addItem.bind(this);
this.deleteTodo = this.deleteTodo.bind(this)
this.getTodos = this.getTodos.bind(this);
this.state = {
todos: TodoStore.getAll(),
};
TodoActions.receiveTodos()
}
componentWillMount() {
TodoStore.addChangeListener(this.getTodos);
}
componentWillUnmount() {
TodoStore.removeChangeListener(this.getTodos);
}
componentDidMount() {
TodoActions.receiveTodos();
}
componentDidUpdate() {
TodoActions.receiveTodos();
}
getTodos() {
this.setState({
todos: TodoStore.getAll(),
});
}
deleteTodo(id) {
TodoActions.deleteTodo(id);
}
addItem(e) {
e.preventDefault();
TodoActions.createTodo(this._inputElement.value)
}
render() {
const { todos } = this.state;
const TodoComponents = todos.map((todo) => {
return (
<div key={todo.id} className="todo-list">
<div className="todo-name">{todo.name}</div>
<div className="todo-btn"><button type="button" onClick={() => this.deleteTodo(todo.id)}>Delete</button></div>
</div>
)
});
return (
<div className="main-container">
<h1 className="title">Todos</h1>
<ul>{TodoComponents}</ul>
<form onSubmit={this.addItem}>
<input ref={(a) => this._inputElement = a} placeholder="Enter Task" className="input-form"/>
<button type="submit" className="input-btn">Add</button>
</form>
</div>
);
}
}
My TodoStore.js
import { EventEmitter } from "events";
import AppDispatcher from "../dispatcher";
let _todos = []
function setTodos(todos) {
_todos = todos;
}
class TodoStore extends EventEmitter {
emitChange = () => {
this.emit("change");
}
addChangeListener = (callback) => {
this.on("change", callback)
}
removeChangeListener = (callback) => {
this.removeListener("change", callback)
}
getAll = () => {
return _todos;
}
handleActions = (action) => {
switch(action.type) {
case "RECEIVE_TODOS": {
setTodos(action.todos);
this.emit("change")
break;
}
}
}
}
const todoStore = new TodoStore;
AppDispatcher.register(todoStore.handleActions.bind(todoStore));
export default todoStore;
My TodoActions.js
import AppDispatcher from "../dispatcher";
import apiClient from "../api-client"
export function createTodo(name) {
apiClient.createTodo({name: name}).then((result) => {
AppDispatcher.dispatch({
type: "CREATE_TODO",
name: result,
});
})
}
export function deleteTodo(id) {
apiClient.deleteTodo(id).then((result) => {
AppDispatcher.dispatch({
type: "DELETE_TODO",
id,
});
})
}
export function receiveTodos() {
apiClient.getAllTodos().then(result => {
AppDispatcher.dispatch({
type: "RECEIVE_TODOS",
todos: result.payload
});
})
}

MobX Store Not Updating In React Native

I have implemented a MobX store in my React-Native app to keep track if a user is being followed or unfollowed. The follow/unfollow is registering, but the MobX store is not being updated. I am trying to update it directly with the this.follows.items[index] = { ...user, isFollowing: !user.isFollowing } but for some reason the store does not trigger an update.
Here is the View Component
#observer
class FollowsListView extends Component<Props> {
follows =
this.props.followType === 'followers'
? followsStore.getFollowersListLoader(this.props.userId)
: followsStore.getFollowingListLoader(this.props.userId);
componentDidMount = () => {
this.follows.lazyLoad();
};
render() {
return (
<>
<AppHeader
title={
this.props.followType === 'followers' ? 'FOLLOWERS' : 'FOLLOWING'
}
/>
<FlatList
contentContainerStyle={{ padding: 15 }}
data={this.follows.items}
keyExtractor={this.getId}
onEndReached={this.follows.loadMore}
onEndReachedThreshold={0.2}
onRefresh={this.follows.loadFromStart}
refreshing={this.follows.isLoading}
renderItem={this.renderFollows}
/>
</>
);
}
private getId = (user: { id: string }) => user.id;
renderUserActionButton(user: UserContainer) {
console.log(user);
return (
user.id !== _SessionManager.id && (
<TouchableOpacity
onPress={() => this.openActionMenu(user.following || user.owner)}
>
<Image source={Images.moreDots} />
</TouchableOpacity>
)
);
}
openActionMenu(user: User) {
const name = user.name || user.username;
const followOption = { name: 'follow', title: `Follow #${name}` };
const unfollowOption = { name: 'unfollow', title: `Unfollow #${name}` };
const options = {
customButtons: [user.isFollowing ? unfollowOption : followOption],
title: null,
takePhotoButtonTitle: null,
chooseFromLibraryButtonTitle: null,
};
ImagePicker.showImagePicker(options, ({ customButton }) => {
if (customButton === 'follow') {
this.props.changeIsFollowingUser(user.id, false);
}
if (customButton === 'unfollow') {
this.props.changeIsFollowingUser(user.id, true);
}
const index = this.follows.items.findIndex((user) => user.id);
this.follows.items[index] = { ...user, isFollowing: !user.isFollowing };
});
}
private renderFollows: ListRenderItem<UserContainer> = ({ item: user }) => {
const userId = user.following ? user.following.id : user.id;
return (
<UserRow
actionContent={this.renderUserActionButton(user)}
onPress={() => this.props.navigateTo('ProfilePublic', { userId })}
user={user.following || user.owner}
/>
);
};
}
const mapDispatchToProps = (dispatch: Function): MappedDispatch =>
bindActionCreators(
{
changeIsFollowingUser,
navigateTo,
},
dispatch
);
export default connect(
null,
mapDispatchToProps
)(FollowsListView);
Here is the Follows Store
import ListLoader from 'Network/ListLoader';
import { Follows } from 'Follows/Types';
import _API from 'Network/API';
class FollowsStore {
followers = new Map<string, Follows>();
followersList = new Map<string, ListLoader<Follows>>();
following = new Map<string, Follows>();
followingList = new Map<string, ListLoader<Follows>>();
getFollowersListLoader(userId: string) {
const list = this.followersList.get(userId);
if (list) return list;
const newList = new ListLoader<Follows>({
fetchData: async (params) => {
const url = `users/${userId}/followers`;
const response = await _API.get(url, { params });
return response.data;
},
onLoad: (data) => {
for (const user of data.items) {
this.followers.set(user.id, user);
}
},
});
this.followersList.set(userId, newList);
return newList;
}
getFollowingListLoader(userId: string) {
const list = this.followingList.get(userId);
if (list) return list;
const newList = new ListLoader<Follows>({
fetchData: async (params) => {
const url = `users/${userId}/following`;
const response = await _API.get(url, { params });
return response.data;
},
onLoad: (data) => {
for (const user of data.items) {
this.following.set(user.id, user);
}
},
});
this.followingList.set(userId, newList);
console.log(newList);
return newList;
}
}
const followsStore = new FollowsStore();
export default followsStore;
In MobX in order to change the state you would need to use an action. Set/decorate your openActionMenu as an action or extract the state changing code to another function which you decorate as action to be cleaner.

Async data loading in Redux-form

I am working with React and Redux, and I'm using Redux-form for my forms.
I am trying to load some initial data from database. In the docs it is recommended to use
{
load: loadAccount
}
in connect component, but I'm struggling to set it properly.
I can load initial data in a different way: adding a dispatch action to connect component and call it from componentDidMount, but I would like to understand how to set { load: loadAccount }.
This is my actions file —I show only the action that matters—:
const actions = {
requestProject: () => {
return {
type: C.LOAD_PROJECT_STARTED,
};
},
receiveProject: (id, data) => {
return {
type: C.LOAD_PROJECT_SUCCESS,
id,
data,
};
},
loadProject: (id = '') => {
const url = '/api/projects/';
const encodedURI = isBrowser
? encodeURI(window.location.origin + url + id)
: encodeURI('http://localhost:' + config.SERVER + url + id);
return isBrowser
? function(dispatch) {
dispatch(actions.requestProject());
return fetch(encodedURI)
.then(
(response) => {
return response.json();
},
(error) => {
return console.log('An error occurred.', error);
}
)
.then((data) => {
return dispatch(actions.receiveProject(id, data));
});
}
: fetch(encodedURI)
.then((response) => {
return response.json();
})
.then((data) => {
return data;
})
.catch((error) => {
return Promise.reject(Error(error.message));
});
},
};
export default actions;
Then my reducers —again, only one—:
export const Project = (state = {}, action) => {
switch (action.type) {
case C.LOAD_PROJECT_STARTED:
console.log('LOAD_PROJECT_STARTED');
return Object.assign({}, state, {
isFetching: true,
});
case C.LOAD_PROJECT_SUCCESS:
return Object.assign({}, state, {
...action.data.Project,
isFetching: false,
});
case C.SUBMIT_PROJECT_FORM_STARTED:
return Object.assign({}, state, {
isFetching: true,
});
case C.SUBMIT_PROJECT_FORM_SUCCESS:
return Object.assign({}, state, {
...action.data.Project,
isFetching: false,
});
default:
return state;
}
};
export const form = formReducer;
This is the connect ProjectForm component for the form:
import { connect } from 'react-redux';
import ProjectFormUi from './ProjectFormUi';
import actions from '../../redux/actions';
import { load as loadAccount } from './account'
export const ProjectForm = connect(
(state) => {
return {
initialValues: state.Project,
};
},
(dispatch) => {
return {
loadProject(id) {
dispatch(actions.loadProject(id));
},
onSubmit(data) {
dispatch(actions.sendingProject(data));
},
};
},
{
load: loadAccount,
}
)(ProjectFormUi);
export default ProjectForm;
And finally, the actual form component, ProjectFormUi.
import React from 'react';
import { Field, reduxForm } from 'redux-form';
class ProjectFormUi extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount() {
this.props.loadProject(1);
}
static getDerivedStateFromProps(newProps, prevState) {
return newProps != prevState ? newProps : null;
}
componentDidUpdate(prevProps) {
if (this.props.Project !== prevProps.Project) {
this.setState({
isFetching: this.props.Project.isFetching,
});
}
}
render() {
const { handleSubmit, load, pristine, reset, submitting } = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<label>First Name</label>
<div>
<Field name="title" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Undo Changes
</button>
</div>
</form>
);
}
}
export default reduxForm({
form: 'ProjectForm',
enableReinitialize: true,
})(ProjectFormUi);
As I said, currently I'm loading data in connect ProjectForm component with:
loadProject(id) {
dispatch(actions.loadProject(id));
},
which is called from componentDidMount in ProjectFormUi component.
But I would like to understand how to load data as in the docs, setting
{
load: loadAccount
}
in connect ProjectForm component.

Is there a way to continuously get an value from a redux store one at a time? react redux

i have a async fetch that gets values like A001, A002, names and so on from an API. But sometimes i get 3 or more values with 1 api fetch and i loose some because i show only 3 values at a time in my react component.
So i look for a way to continuously show 1 entry from the store for like 2 seconds and then the next entry and so on.
Can someone please help me here?
Actions
let lastId = 0;
let pathArray = window.location.pathname.split('/');
export const fetchLastId = () => dispatch => {
const url = '/api/display/sites/' + pathArray[3] + '/displays/' + pathArray[5] + '/show';
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Authorization': ''
},
'Content-Type': 'application/json'
}).then(function(response) {
return response.json();
}).then(function(data) {
if (data.length) {
lastId = data[0].id;
} else {
lastId = 0;
}
console.log('Die Letzte ID war ' + lastId);
}).catch(function(error) {
console.log('Fehler: ', error);
})
}
export const fetchLastCalls = () => dispatch => {
const url = '/api/display/sites/' + pathArray[3] + '/displays/' + pathArray[5] + '/calls?id_greater_than=' + lastId;
fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Authorization': ''
},
'Content-Type': 'application/json'
}).then(function(response) {
return response.json();
}).then(function(data) {
data.reverse();
if (data.length) {
for (let item of data) {
switch (item.service_id) {
case 24:
dispatch({ type: 'SERVICE_1', payload: item })
break;
case 25:
dispatch({ type: 'SERVICE_2', payload: item })
break;
default:
console.log('Aufruf im Falschen Dienst getätigt.')
}
lastId = item.id;
}
} else {
console.log('Keine neuen Aufrufe.');
}
}).catch(function(error) {
console.log('Fehler: ', error);
})
}
Reducer
let initialState = [];
function service1(state = initialState, action) {
if (action.type === 'SERVICE_1') {
return [action.payload, ...state];
}
return state;
}
export default service1;
Container
import React from 'react';
import { connect } from 'react-redux';
import { NewCall } from '../components/NewCall';
import { LastCall } from '../components/LastCall';
import { fetchLastId , fetchLastCalls } from '../actions/index';
class Service1 extends React.Component {
componentWillMount() {
this.props.onFetchLastId();
}
componentDidMount() {
setInterval(function() {
this.props.onFetchLastCalls();
}.bind(this), 1000);
}
renderNewTicket() {
return this.props.calls.map(call => {
return (
<p key={call.ticket}>{call.ticket}</p>
);
});
}
renderNewPlace() {
return this.props.calls.map(call => {
return (
<p key={call.desk_id}>{call.desk_id}</p>
);
});
}
renderLastTicket() {
return this.props.calls.map(call => {
return (
<p key={call.ticket}>{call.ticket}</p>
)
})
}
renderLastPlace() {
return this.props.calls.map(call => {
return (
<p key={call.desk_id}>{call.desk_id}</p>
)
})
}
componentDidUpdate() {
}
render() {
return(
<div>
<NewCall
call={ this.renderNewTicket() }
place={ this.renderNewPlace() }
/>
<LastCall
call={ this.renderLastTicket() }
place={ this.renderLastPlace() }
rollOn={1}
/>
<LastCall
call={ this.renderLastTicket() }
place={ this.renderLastPlace() }
rollOn={2}
/>
</div>
);
}
}
function mapStateToProps(state) {
return {
calls: state.service1
};
}
let mapDispatchToProps = {
onFetchLastId: fetchLastId,
onFetchLastCalls: fetchLastCalls
}
export default connect(mapStateToProps, mapDispatchToProps)(Service1);
1 Output Component
import React from 'react';
import { Textfit } from 'react-textfit';
import Blink from './Blink';
const inlineStyle = {
width: 945,
height: 249
};
export class NewCall extends React.Component {
render() {
return(
<div>
<div className="flex-item-grey ticketNrGr">
<Textfit mode="multi" style={inlineStyle} className="textfit" max={200}><Blink>{this.props.call[0]}</Blink></Textfit>
</div>
<div className="flex-item-grey platzNrGr">
<Textfit mode="multi" style={inlineStyle} className="textfit" max={200}><Blink>{this.props.place[0]}</Blink></Textfit>
</div>
</div>
);
}
}
Second Output Component
import React from 'react';
import { Textfit } from 'react-textfit';
const inlineStyleCall = {
width: 735,
height: 195
};
const inlineStyleDesk = {
width: 200,
height: 195
};
export class LastCall extends React.Component {
render() {
return(
<div className="flex-container-aufrufKl">
<div className="flex-item-grey ticketNrKl">
<Textfit mode="multi" style={inlineStyleCall} className="textfit" max={200}>{this.props.call[this.props.rollOn]}</Textfit>
</div>
<div className="flex-item-grey platzNrKl">
<Textfit mode="multi" style={inlineStyleDesk} className="textfit" max={200}>{this.props.place[this.props.rollOn]}</Textfit>
</div>
</div>
);
}
}
It sounds to me like it should be the responsibility of the component to trigger a new action to render the next available value. So you could have a component that accepts the value value and a boolean indicating if there are any more values: hasMoreValues.
In your react component, you'll need to make it a class to access the lifecycle hooks and hook into the componentDidMount function:
class MyComponent extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
if(this.props.hasMoreValues) {
setTimeout(this.props.showNextValue, 2000)
}
}
render() {
return (
<div>{this.props.value}</div>
)
}
}
export default connect(
(props) => ({
hasMoreValues: getHasMoreValues(),
value: getNextValue(),
)},
{
showNextValue: () => { type: 'SHOW_NEXT_ACTION' },
},
)
An approach like this means that the trigger is still coming from the application. The next thing to do is update the item to view to be the next one available in your reducer, but I'll leave that up to you.

Categories

Resources