Uploading multiple files using react and Django REST API - javascript

I am building a project in which users can upload videos in bulk, My code works fine but I want to show the users a progress bar when their videos are being uploaded to the server, By doing some research on the internet I found that the onUploadProgress event of Axios can be used, but I have no idea on how to send the upload progress of each video file individually.
Below is my code
reducers.js file-
import * as actionTypes from "../actions/types";
const intialState = {
isLoading: false,
uploadProgress: 0,
error: null
};
export default function(state = intialState, action) {
switch (action.type) {
case actionTypes.ADD_VIDEO_START:
case actionTypes.ADD_VIDEO_SUCCESS:
case actionTypes.ADD_VIDEO_ERROR:
return {
...state,
isLoading: action.isLoading,
error: action.error
};
case actionTypes.VIDEO_UPLOAD_PROGRESS:
return {
...state,
uploadProgress: action.percentage
};
default:
return state;
}
}
actions.js
import * as actionTypes from "./types";
import { getToken, VIDEO_URL } from "./Utils";
import axios from "axios";
export const addVideos = video => dispatch => {
if (getToken()) {
dispatch({
type: actionTypes.ADD_VIDEO_START,
isLoading: true,
error: null,
});
const config = {
headers: {
Accept: "application/json",
"Content-Type": "multipart/form-data",
Authorization: `Token ${getToken()}`
},
onUploadProgress: progressEvent => {
const { loaded, total } = progressEvent;
let percentage = Math.floor((loaded * 100) / total);
dispatch({
type: actionTypes.VIDEO_UPLOAD_PROGRESS,
percentage: percentage
});
}
};
let form_data = new FormData();
form_data.append("video", video);
axios
.post(COURSE_CONTENT_URL, form_data, config)
.then(() =>
dispatch({
type: actionTypes.ADD_VIDEO_SUCCESS,
isLoading: false,
error: null
})
)
.catch(error =>
dispatch({
type: actionTypes.ADD_VIDEO_ERROR,
isLoading: false,
error: error,
})
);
} else {
console.log("You are not authenticated");
}
};
videoComponent.js
...
const courseContent = {
video: [], // <- All the videos to be uploded are kept here
};
//submit function
const handleSubmit = () => {
courseContent.video.map(file => props.addVideos(file));
};
...
views.py
...
#api_view(['POST'])
#parser_classes([FormParser, MultiPartParser])
#authentication_classes([TokenAuthentication])
#permission_classes([IsAuthenticated])
def add_content(request):
models.Videos.objects.create(
user=request.user,
video=request.FILES.get('video')
)
return Response(status=status.HTTP_201_CREATED)
...
Any help on this would be much appreciated.

Related

useSelector not updating state changes

I am struggling to figure the issue here.
There is a subscribe and unsubscribe to a podcast.
When I hit either the database gets updated (firebase) but it doesn't trigger a re-render via the useSelector. If I hit the button again, it'll re-render and the useSelector values will update.
Appreciate any help
Here is the component
const PodcastDetailsScreen = ({ route }) => {
const podcastDetails = route.params;
const [podcastEpisodeDetails, setPodcastEpisodeDetails] = useState("");
const {
data: userInfo,
data: { subscriptions: userSubscriptions },
} = useSelector((state) => state.userLogin);
console.log("userInfo111", userInfo);
console.log(userSubscriptions);
useEffect(() => {
getPodcastDetailsLN(podcastDetails.id, setPodcastEpisodeDetails);
}, [podcastDetails.id]);
const timeAgo = new TimeAgo("en-US");
const dispatch = useDispatch();
const subscribeHandler = async () => {
console.log("subscribeHandler");
dispatch(addUserSubscription(userInfo.uid, podcastDetails.id));
};
const unsubscribeHandler = async () => {
console.log("unsubscribeHandler");
dispatch(removeUserSubscription(userInfo.uid, podcastDetails.id));
};
return (
Here are the two actions
// Add user subscription to firestore
export const addUserSubscription = (userId, podcastId) => async (dispatch) => {
try {
dispatch({ type: USER_SUBSCRIPTIONS_REQUEST });
const docRef = doc(db, "users", userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const subscriptions = docSnap.data().subscriptions;
subscriptions.push(podcastId);
await setDoc(docRef, { subscriptions }, { merge: true });
dispatch({ type: USER_SUBSCRIPTIONS_SUCCESS, payload: subscriptions });
} else {
console.log("2");
dispatch({ type: USER_SUBSCRIPTIONS_FAILURE, payload: "ERROR: No user exists?" });
}
} catch (error) {
dispatch({ type: USER_SUBSCRIPTIONS_FAILURE, payload: error.message });
}
};
// Remove user subscription from firestore
export const removeUserSubscription = (userId, podcastId) => async (dispatch) => {
try {
dispatch({ type: USER_SUBSCRIPTIONS_REQUEST });
const docRef = doc(db, "users", userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const subscriptions = docSnap.data().subscriptions;
const newSubscriptions = subscriptions.filter((sub) => sub !== podcastId);
await setDoc(docRef, { subscriptions: newSubscriptions }, { merge: true });
dispatch({ type: USER_SUBSCRIPTIONS_SUCCESS, payload: newSubscriptions });
} else {
dispatch({
type: USER_SUBSCRIPTIONS_FAILURE,
payload: "ERROR: no sublist or couldn't find it",
});
}
} catch (error) {
dispatch({ type: USER_SUBSCRIPTIONS_FAILURE, payload: error.message });
}
};
And here are the reducers
// Load user info into state after signup or login
export const userLoginReducer = (state = {}, action) => {
switch (action.type) {
case USER_LOGIN_REQUEST:
return {
...state,
loading: true,
};
case USER_LOGIN_SUCCESS:
return {
...state,
loading: false,
data: action.payload,
};
case USER_LOGIN_FAILURE:
return {
...state,
loading: false,
error: action.payload,
};
// Add user subscription
case USER_ADD_SUBSCRIPTION_REQUEST:
return { ...state, loading: true };
case USER_ADD_SUBSCRIPTION_SUCCESS:
return {
...state,
loading: false,
success: true,
data: { subscriptions: action.payload },
};
case USER_ADD_SUBSCRIPTION_FAILURE:
return { ...state, loading: false, success: false, error: action.payload };
// --------------------------------------------------
// Remove user subscription
case USER_REMOVE_SUBSCRIPTION_REQUEST:
return { ...state, loading: true };
case USER_REMOVE_SUBSCRIPTION_SUCCESS:
return {
...state,
loading: false,
success: true,
data: { subscriptions: action.payload },
};
case USER_REMOVE_SUBSCRIPTION_FAILURE:
return { ...state, loading: false, success: false, error: action.payload };
// --------------------------------------------------
default:
return state;
}
};

401 Unauthorized, SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Hi all I'm new to authentication. I was building an app where a user can login and create a story using an api, and the story is sent to the backend using a POST request. The app was authenticating fine, until I built the app. Now when I sign in and try to add a story, I get 401 Unauthorized and SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data in actions.js.
Then if I refresh the page, the errors go away and the app is working.
I am able to logout and login again normally.
I have no idea why that's happening. Any help will be appreciated.
The backend server does say Error in authorization JsonWebTokenError: jwt malformed
actions.js
import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';
import { getToken } from '../utils/Common'
const token = getToken();
// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
return {
type: t.SET_LOGIN_STATE,
payload: loginData, //{ ...json, userId: email }
};
};
const setStoryState = (storyData) => {
return {
type: t.CREATE_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getStoryState = (storyData) => {
return {
type: t.GET_STORIES,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getSingleStoryState = (storyData) => {
return {
type: t.GET_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
export const login = (loginInput) => { //our login action
const { email, password, isAdmin } = loginInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(loginInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
// console.log(json)
dispatch(setLoginState({ ...json, userId: email, isAdmin: isAdmin })); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
setUserSession(json.token, json.lastName)
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
};
export const getStories = () => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getStoryState( [...json ])); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const viewStory = id => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getSingleStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const roleChange = () => {
return {
type: t.SET_ROLE_STATE,
//payload: role
};
}
export const logout = () => {
return {
type: t.LOGOUT,
};
}
export const createStory = storyInput => {
console.log(token)
const { summary, description, type, complexity, time, cost } = storyInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify(storyInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
//dispatch(setStoryState( [...json ]));
dispatch(setStoryState({ // our action is called here with object as parameter, this is our payload
summary: summary,
description: description,
type: type,
complexity: complexity,
time: time,
cost: cost
})); // our action is called here
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Some error occured, please retry');
console.log(err);
});
};
}
export const addStory = story => {
return {
type: t.ADD_STORY,
payload: story,
}
}
export const setStatus = (id, status) => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}/${status}`, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'text/html',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
// dispatch(getStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
CreateStory.js
import React, { useState } from 'react'
import { createStory } from '../redux/actions'
import { useDispatch, useSelector } from "react-redux";
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const CreateStory = () => {
const [summary, setSummary] = useState("");
const [description, setDescription] = useState("");
const [type, setType] = useState("");
const [complexity, setcomplexity] = useState("");
const [time, setTime] = useState("");
const [cost, setCost] = useState(0);
const usedispatch = useDispatch();
const userCreateStory = (summary, description, type, complexity) => usedispatch(createStory({
'summary': summary,
'description': description,
'type': type,
'complexity': complexity,
'time': time,
'cost': cost
}));
const handleSummaryChange = e => {
setSummary(e.target.value)
}
const handleDescriptionChange = e => {
setDescription(e.target.value)
}
const handleTypeChange = e => {
setType(e.target.value)
}
const handleComplexityChange = e => {
setcomplexity(e.target.value)
}
const handleTimeChange = e => {
setTime(e.target.value)
}
const handleCostChange = e => {
setCost(e.target.value)
}
// const currStory = useSelector((state)=> state.storyReducer.story)
const handleSubmit = e => {
e.preventDefault();
userCreateStory(summary,description,type,complexity,time,cost)
setTimeout(()=> history.push("/userStories"), 1000 );
//setTimeout(()=> console.log(currStory) ,1000)
}
return (
<div>
<form className='create-story-form'>
<label for="summary">Summary:</label>
<input name="summary" type='text' onChange={handleSummaryChange}/>
<label for="desc">Description:</label>
<textarea name="desc" type='text' onChange={handleDescriptionChange}/>
<label for="type">Type:</label>
<select name="type" onChange={handleTypeChange}>
<option value="enhancement" defaultValue>Enchancement</option>
<option value="bugfix">Bugfix</option>
<option value="development">Development</option>
<option value="qa">QA</option>
</select>
<label for="complexity">Complexity:</label>
<select name="complexity" onChange={handleComplexityChange}>
<option value="low" defaultValue>Low</option>
<option value="mid">Mid</option>
<option value="high">High</option>
</select>
<label for="time">Estimated time for completion:</label>
<input name="time" type='text' onChange={handleTimeChange}/>
<label for="cost">Cost:</label>
<input name="cost" type='number' onChange={handleCostChange}/>
<button onClick={handleSubmit}>Submit</button>
</form>
</div>
)
}
export default withRouter(CreateStory);
Login.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { login, roleChange } from '../redux/actions' //OUR ACTIONS
import { useSelector } from 'react-redux'
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const usedispatch = useDispatch();
const userLogin = (email, password, isAdmin) => usedispatch(login({'email': email, 'password': password, 'isAdmin': isAdmin }));
const handleRoleChange = e => {
setIsAdmin(true)
if(isAdmin)
setIsAdmin(false)
console.log(isAdmin)
}
const handleEmailChange = e => {
setEmail(e.target.value)
}
const handlePasswordChange = e => {
setPassword(e.target.value)
}
const handleSubmit = e => {
e.preventDefault();
userLogin(email, password, isAdmin)
setTimeout(()=> history.push("/user"), 1000 );
}
const disabled = () => {
return email === "" || password === ""
}
return (
<div>
<form className='login-form'>
<input type='email' name='email' placeholder='Email' onChange={handleEmailChange}/>
<input type='password' name='password' placeholder='Password' onChange={handlePasswordChange}/>
<button type='submit' disabled={disabled()} onClick={handleSubmit}>Login</button>
</form>
<button onClick={handleRoleChange}>Switch to {isAdmin ? 'user' : 'admin'}</button>
</div>
)
}
export default withRouter(Login);
reducers.js
import { initialState } from './initialState';
import * as t from './actionTypes';
export const loginReducer = (state = initialState, action) => {
switch (action.type) {
case t.SET_ROLE_STATE:
return {
...state,
isAdmin: true
};
case t.SET_LOGIN_STATE:
return {
...state,
...action.payload, // this is what we expect to get back from API call and login page input
isLoggedIn: true, // we set this as true on login
};
case t.LOGOUT:
return {
initialState
};
default:
return state;
}
};
export const storyReducer = (state = [], action) => {
switch (action.type) {
case t.CREATE_STORY:
return {
...state,
stories: [...state.stories, action.payload],
};
case t.GET_STORIES:
return {
...state,
stories: action.payload,
};
case t.GET_STORY:
return {
...state,
story: action.payload,
};
// case t.ADD_STORY:
// return {
// ...state,
// stories: [...state.stories, action.payload], //stories is an object
// };
case t.LOGOUT:
return {
stories: [{complexity: "",
cost: 0,
description: "",
summary: "",
time: "",
type: ""}]
};
default:
return state;
}
}

Creating posts with react redux

I'm a junior dev and have just joined recently. I'm trying to create a blog-like website where users can save a post and update an already saved post. I'm currently confused as to how to assign the snippetId within the post.
So this website was already made in Angular and I've been asked to migrate it to React. I'm mostly confused about how to store the ID as it is received from the server in response.data for a new post, and also, how I would receive it in the action.js file from the Redux store if it already exists.
Please help me understand the snippetData['snippetId'] part from the Angular and if I should I even use snippetData in the initialState or just use snippetId, snippetDescription, snippetTitle directly in the `initialState.
My code for now looks something like this:
action.js
import { SAVE_POST } from './types';
export const savePost=({snippetId, snippetDescription, snippetTitle})=> async dispatch=>{
const config = {
headers: {
'Content-Type': 'application/json'
}
}
}
const body = JSON.stringify({snippetId, snippetDescription, snippetTitle});
try{
if(snippetId==null){
const res = await axios.post('/api/save', body, config);
dispatch({
type: SAVE_POST,
payload: res.data
});}
else{
snippetData['snippetId']=snippetId
const res = await axios.post('/api/update', body, config);
dispatchEvent({
type: UPDATE_POST,
payload: res.data
})
}
}catch(err){
console.log(err);
}
reducer/post.js
import { SAVE_POST} from '../actions/types';
const initialState={
snippetData: {
snippetId: null,
snippetTitle: null,
snippetDescription: null
}
};
export default function (state=initialState, action){
const {type, payload}=action;
switch(type){
case SAVE_POST:
return {...state,
snippetData: {
snippetId: payload,
snippetDescription: payload,
snippetTitle: payload}
case UPDATE_POST:
return {...state,
snippetId: payload,
snippetDescription: payload,
snippetTitle: payload
}
}
}
This is finally the Angular file from where I've been asked to translate to React:
$scope.savesnippet=function(){
$scope.snippetdata={}
$scope.snippetdata['snippetTitle']=$scope.snippetTitle
$scope.snippetdata['snippetDescription']=$scope.snippetDescription
console.log($scope.snippetId)
if($scope.snippetId==null){
return $http.post('/api/save',$scope.snippetdata).then(function(response){
if(response.status==200){
$scope.snippetId=response.data;
toaster.pop('success','Snippet saved successfully!')
}else{
toaster.pop('danger','An error has occured while saving the snippet. Please try again')
}
});
}else{
$scope.snippetdata['snippetId']=$scope.snippetId
return $http.post('/api/update',$scope.snippetdata).then(function(response,status){
if(response.status==200){
toaster.pop('success','Snippet saved successfully!')
}else{
toaster.pop('danger','An error has occured while updating the snippet. Please try again')
}
});
}
}
edit:
editor.js
performSave = (snippetData) => {
const {enteredText, title} = this.state;
let {snippetId, snippetDescription, snippetTitle} = snippetData;
snippetTitle=title;
snippetDescription=enteredText;
savePost(snippetId, snippetDescription, snippetTitle);
}
const mapStateToProps = state=>({
snippetData: state.snippetData
})
export default connect(mapStateToProps, {savePost})(Editor);
What i understand from you given angular code, on API save success, you dont get entire data. U only get id of the save data. So in payload you need to update snippetId.
In case of save success, you dont need any update. U can just use as payload.
import { SAVE_POST } from "./types";
export const savePost = ({
snippetId,
snippetDescription,
snippetTitle
}) => async dispatch => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
let snippetData = { snippetId, snippetDescription, snippetTitle };
try {
if (snippetId == null) {
const res = await axios.post("/api/save", JSON.stringify(snippetData), config);
snippetData.snippetId = res.data
dispatch({
type: SAVE_POST,
payload: snippetData
});
} else {
const res = await axios.post("/api/update", JSON.stringify(snippetData), config);
dispatchEvent({
type: UPDATE_POST,
payload: snippetData
});
}
} catch (err) {
console.log(err);
}
};
// Reducer:
import { SAVE_POST } from "../actions/types";
const initialState = {
snippetData: {
snippetId: null,
snippetTitle: null,
snippetDescription: null
}
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case SAVE_POST:
return {
...state,
snippetData: payload
};
case UPDATE_POST:
return {
...state,
snippetData: payload
};
}
}

How to dispatch from actioncreator to reducer wihout error in one time?

I am dispatching an image to firebase. Everything is successful and I can upload the image to firebase storage. But after I got success, my codes was suddenly dispatched an error one more time.By the way I logged some numbers to see what's going on and I got "1,2,3,4 then success and then failed error" on my console. How can I achive to upload image without getting failed error? I could upload but I also get error now.. Thank you in advance..
The error message says: "Invalid attempt to spread non-iterable instance".
export const uploadPhoto = (uri, contentType = 'image/jpeg') => {
return async dispatch => {
try {
console.log('1');
const userId = firebase.auth().currentUser.uid;
const photoId = await uniqueIdGenerator();
dispatch({ type: UPLOAD_START });
console.log('2');
const snapshot = await firebase.storage().ref()
.child(`/photos/${userId}`)
.child(photoId)
.put(uri, { contentType });
console.log('3');
await firebase.firestore()
.collection('users').doc(userId)
.collection('photos').doc(photoId)
.set({ url: snapshot.downloadURL });
console.log(snapshot.downloadURL);
console.log('4');
await dispatch({ type: UPLOAD_SUCCESS, payload: snapshot.downloadURL });
console.log('5');
Actions.pop();
console.log('6');
}
catch (error) {
dispatch({ type: UPLOAD_FAILED });
console.log(error.message);
}
}
}
here is my reducer:
const INITIAL_STATE = {
data: [],
loading: false
}
export default (state = INITIAL_STATE, { type, payload }) => {
console.log('reducerState', state);
console.log('type,payload', type, payload);
switch (type) {
case UPLOAD_START:
return { ...state, data: payload, loading: true }
case UPLOAD_SUCCESS:
console.log('succesa girdi');
return { ...state, data: [...state.data, payload], loading: false }
case UPLOAD_FAILED:
return { ...state, data: payload, loading: false }
case GET_PHOTOS_START:
return { ...state, data: payload, loading: true }
case GET_PHOTOS_SUCCESS:
return { ...state, data: payload, loading: false }
case GET_PHOTOS_FAILED:
return { ...state, data: payload, loading: false }
default:
return state;
}
}
EDIT
I have figured out the problem by remove all the dumy datas from my firebase storage. I use an emulator to test my app and I used same photos again and again. Most probably same photos causes a problem because I have not changed anything else in my app but now is working well.
Try to change your reducer
case UPLOAD_SUCCESS:
console.log('succesa girdi');
return { ...state, data: [...state.data, payload], loading: false }
to
case UPLOAD_SUCCESS:
console.log('succesa girdi');
return { ...state, data: payload, loading: false }
I think there is what the error is trying to warn you about. I'm not sure why you are trying to spread the state twice
UPDATE
in that case try this
case UPLOAD_SUCCESS:
console.log('succesa girdi');
let urls= state.data
urls.push(payload)
return { ...state, data: urls, loading: false }

How to handle multiple api request,to show loading indicator from one variable in redux store

i wanted to show loader for each and every request individually depending on what request made,Suppose in dashboard i have muiltple widget and they all have different api call, i wanted to show different loader for each request made,
one way is to make adding isLoading flag for every request made,which i think is not the good solution as the application grows,and i am finding solution that can handle multiple request from one flag
so how should i do to make dynamic individual loader based on every request
below is my reducer and action
reducer
export const intialstate = {
isAuth: false,
isLoading: false,
btnDisable: false
};
export default function(state = intialstate, action) {
switch (action.type) {
case API_REQUEST:
return {
...state,
isLoading: true,
};
case API_SUCCESS:
return {
...state,
isLoading: false,
isError: null
};
case API_FAILURE:
return {
...state,
isError: action.payload,
isLoading: false,
};
// no default
}
return state;
}
action.js
export const AnyAPIRequest = () => {
return (dispatch) => {
dispatch({
type: API_REQUEST
});
API.anygetcall()
.then((res) => {
dispatch({
type: API_SUCCESS
});
dispatch({ type: GETLIST, payload: res });
})
.catch((err) => {
dispatch({
type: API_FAILURE,
payload: err
});
});
};
};
Please help,how to implement dynamic loader based on different request and let me know any thing to update in current workflow
Two ways:
Have an integer count of API calls loading. IsLoading: IsLoading + 1 and then show the loading indicator if IsLoading > 1
Name each of your IsLoading differently to show different loading indicators. For example if you had a call to get students and a call to get teachers, you would have IsLoadingStudents and IsLoadingTeachers and have separate loading indicators for each component in the app
If you don't want to add a new isLoadingXXX for each new API request, you can use a collection and give each API request a string ID. Something like the following:
Reducer:
export const intialstate = {
isAuth: false,
isLoadingRequestIds: [],
btnDisable: false
};
export default function(state = intialstate, action) {
switch (action.type) {
case API_REQUEST:
return {
...state,
isLoadingRequestIds: [...state.isLoadingRequestIds, action.requestId],
};
case API_SUCCESS:
return {
...state,
isLoadingRequestIds:
state.isLoadingIds.splice(state.isLoadingRequestIds.indexOf(action.requestId)).slice(),
isError: null
};
case API_FAILURE:
return {
...state,
isError: action.payload,
isLoadingRequestIds:
state.isLoadingIds.splice(state.isLoadingRequestIds.indexOf(action.requestId)).slice(),
};
// no default
}
return state;
}
Actions:
export const AnyAPIRequest = (requestId) => {
return (dispatch) => {
dispatch({
requestId,
type: API_REQUEST
});
API.anygetcall()
.then((res) => {
dispatch({
requestId,
type: API_SUCCESS
});
dispatch({ type: GETLIST, payload: res });
})
.catch((err) => {
dispatch({
requestId,
type: API_FAILURE,
payload: err
});
});
};
};
export const StudentAPIRequest = () => AnyAPIRequest('student');
export const TeacherAPIRequest = () => AnyAPIRequest('teacher');

Categories

Resources