Hi first post here so please go easy with me. I new to redux and wondered why im not get a rerender when my store is being updated successfully.
here is my reducer
const initialState = {
pending: false,
loadPlanning: [],
error: null
}
export const loadPlanningReducer = (state = initialState, action) => {
if (action.type === INITIALISE_LOAD_PLANNING_PENDING) {
return {
...state,
pending: true
}
}
if (action.type === INITIALISE_LOAD_PLANNING_SUCCESS) {
console.log('updating state');
return Object.assign({}, state, {
...state,
pending: false,
loadPlanning: state.loadPlanning.concat(action.loadPlanning.items)
});
}
if (action.type === INITIALISE_LOAD_PLANNING_ERROR) {
return {
...state,
pending: false,
error: action.error
}
}
return state;
}
export default loadPlanningReducer;
export const getLoadPlanning = (state) => { console.log('reducer state',state); return state.loadPlanning };
export const getLoadPlanningPending = (state) => state.pending;
export const getLoadPlanningError = (state) => state.error;
The view looks like
const mapStateToProps = (state, ownProps) => ({
error: getLoadPlanningError(state),
loadPlanning: getLoadPlanning(state),
pending: getLoadPlanningPending(state),
options: state.options.options,
option: state.options.currentOption,
oidc: state.oidc
})
const mapDispatchToProps = (dispatch) => {
return {
dispatch
};
}
const fetchLoadPlanning = async (props) => {
props.dispatch(initialiseLoadPlanning());
const httpOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${xxxxxxxx}`
}
};
fetch('/Api/Planning/Get_Data?' + "database=xxxxxx", httpOptions)
.then(res => res.json())
.then(res => {
if (res.hasError) {
throw res.error;
}
props.dispatch(initialiseLoadPlanningSuccess(res.data));
return res.data;
})
.catch(error => {
props.dispatch(initialiseLoadPlanningError(error));
});
}
const LoadPlanningList = (props) => {
useEffect(() => {
fetchLoadPlanning(props);
}, [])
useEffect(() => {
console.log('props changed',props);
},[props])
}
The console log of props changed happens on change of props.pending but not on the dispatch of props.dispatch(initialiseLoadPlanningSuccess(res.data));
console log
You help and wisdom would be most helpful, thanks in advance
Related
In my fullfilled i am getting response as undefined. any one please help?
code :
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import axios from "axios";
const fetchPost = createAsyncThunk('fetch/post', async (params: string) => {
try {
const { data } = await axios.get('https://registry.npmjs.org/-/v1/search', { params: { text: params } })
data.objects.map((result: any) => {
console.log('result', result)//getting result
return result.package.name;
});
} catch (err: any) {
return err?.response;
}
})
interface RepositoriesState {
loading: boolean;
error: string | null;
data: string[];
}
const initialRepoState:RepositoriesState = {
loading: false,
error: null,
data:[]
}
const repositorySlice = createSlice({
name: 'repo-slice',
initialState: initialRepoState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchPost.pending, (state) => {
state.loading = true
})
.addCase(fetchPost.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
console.log('payload', action.payload) //undefined
})
.addCase(fetchPost.rejected, (state) => {
state.loading = false;
state.error = "error in api";
state.data = [];
})
}
})
export { fetchPost };
export default repositorySlice.reducer;
Nothing is getting returned from your function... so its undefined
I guess it should be as so
const fetchPost = createAsyncThunk('fetch/post', async (params: string) => {
try {
const { data } = await axios.get('https://registry.npmjs.org/-/v1/search', { params: { text: params } })
return data.objects.map((result: any) => {
console.log('result', result)//getting result
return result.package.name;
});
} catch (err: any) {
return err?.response;
}
})
I'm trying to fetch a list from database and add to my state. but the action.payload is undefined on the api the result is correct.
mySlice
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import { fileFetch } from "./fileAPI";
const initialState = {
loading: "idle" | "pending" | "succeeded" | "failed",
error: false,
filesUploaded: null,
};
export const fetchFiles = createAsyncThunk("files/fetchFiles", () => {
return fileFetch();
});
export const fileSlice = createSlice({
name: "files",
initialState,
reducers: {},
extraReducers(builder) {
builder
.addCase(fetchFiles.pending, (state, action) => {
state.loading = "pending";
})
.addCase(fetchFiles.fulfilled, (state, action) => {
console.log(action);
state.loading = "succeeded";
state.filesUploaded = action.payload;
})
.addCase(fetchFiles.rejected, (state, action) => {
state.loading = "failed";
state.filesUploaded = [];
state.error = action.error.message;
});
},
});
export default fileSlice.reducer;
myAPI
const api = axios.create({
baseURL: "http://localhost:8081/file/",
headers: {
"content-type": "application/json",
},
});
export const fileFetch = async () => {
await api
.get("getAll")
.then((res) => {
console.log(res.data);
return res.data;
})
.catch((err) => {
throw new Error(err);
});
};
the console.log on the api is returning the correct data.
any idea why the payload is undefined?
thanks.
Might be because you are using both async-await and Promise methods in fileFetch function. Try updating it to this
export const fileFetch = async () => {
const response = await api.get("getAll")
return response.data
};
myApi
export const fileFetch = () => api.get("getAll")
mySlice
export const fetchFiles = createAsyncThunk(
"files/fetchFiles",
async ({ rejectWithValue }) => {
try {
const response = await fileFetch();
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
Also working lifecycle methods
isAuthenticated is undefined when i run this code. how can is use isAuthenticated with mapStateProps. if i am use Token `(Token '5302f4340a76cd80a855286c6d9e0e48d2f519cb'} like this then it's working fine but i want Authorized it with props.isAuthenticated anybody know how can i solve this issue?
authAction.js
import axios from 'axios';
import * as actionTypes from './actionTypes';
export const authStart = () => {
return {
type: actionTypes.AUTH_START
}
}
export const authSuccess = token => {
return {
type: actionTypes.AUTH_SUCCESS,
token: token
}
}
export const authFail = error => {
return {
type: actionTypes.AUTH_FAIL,
error: error
}
}
export const logout = () => {
localStorage.removeItem('token');
return {
type: actionTypes.AUTH_LOGOUT
};
}
export const authLogin = (userData) => {
return dispatch => {
dispatch(authStart());
axios.post('http://localhost:8000/rest-auth/login/', userData)
.then(res => {
const token = res.data.key;
localStorage.setItem('token', token);
dispatch(authSuccess(token));
})
.catch(err => {
dispatch(authFail(err))
})
}
}
authReducer.js
import * as actionTypes from '../actions/actionTypes';
import { updateObject } from '../utility';
const initialState = {
isAuthenticated: null,
token: null,
error: null,
loading: false
}
const authStart = (state, action) => {
return updateObject(state, {
isAuthenticated: false,
error: null,
loading: true
});
}
const authSuccess = (state, action) => {
return updateObject(state, {
isAuthenticated: true,
token: action.token,
error: null,
loading: false
});
}
const authFail = (state, action) => {
return updateObject(state, {
error: action.error,
loading: false
});
}
const authLogout = (state, action) => {
return updateObject(state, {
token: null
});
}
export default function (state = initialState, action) {
switch (action.type) {
case actionTypes.AUTH_START: return authStart(state, action);
case actionTypes.AUTH_SUCCESS: return authSuccess(state, action);
case actionTypes.AUTH_FAIL: return authFail(state, action);
case actionTypes.AUTH_LOGOUT: return authLogout(state, action);
default:
return state;
}
}
index.js
import { combineReducers } from 'redux';
import auth from './authReducer'
export default combineReducers({
auth: auth
});
articleList.js
const NewsList = (props) => {
// ...
const fetchItems = async () => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${props.isAuthenticated}`
}
}
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/`, config);
setItems(res.data)
setLoading(false);
}
catch (err) {
console.log(`😱 Axios request failed: ${err}`);
}
}
fetchItems()
})
}, [items]);
// ...
}
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token
}
}
export default connect(mapStateToProps)(NewsList)
You need to debug your code. Start by connecting the dots: The output tells you that props.isAuthenticated is undefined. You pass this in from state.auth.token in mapStateToProps():
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token
}
}
So state.auth.token must be undefined also. That's as far as I can get from what you have shown me. You will need to debug further to figure out why. You can use the React Dev Tools to inspect props of your components. You can use Redux Dev Tools to inspect and manipulate the redux state. Check what the value of auth.token is in state. Look where it is supposed to be set and find out why it isn't getting set to a valid value.
Be sure to check this article for tips on how to debug your code.
I am learning React Redux. My Action is like below
import Axios from 'axios';
export const getAddress = valueModal => dispatch => {
return Axios.get('/api/address')
.then(response => {
var addressData = response.data;
dispatch({
type: 'getAddresses',
payload: { addressData, valueModal }
});
})
.catch(function(error) {
console.log(error);
});
};
export const uploadImage = (formData, id, config) => dispatch => {
return Axios.post('/api/address/upload', formData, config)
.then(response => {
dispatch({
type: 'uploadImage',
payload: response.data
});
})
.catch(function(error) {
console.log(error);
});
};
export default { getAddress, addAddress, uploadImage };
My Reducer is like below
const initialState = {
address: {}
};
const addressReducer = (state = initialState, action) => {
switch (action.type) {
case 'getAddresses': {
return {
controlModal: action.payload.valueModal,
address: action.payload.addressData
};
}
case 'uploadImage': {
return {
uploadImage: action.payload
};
}
default:
return state;
}
};
export default addressReducer;
I would like to call getAddresses and uploadImage jointly. How can I do that ?
const initialState = {
address: {}
};
const addressReducer = (state = initialState, action) => {
switch (action.type) {
case 'getAddresses': {
return {
...state,
controlModal: action.payload.valueModal,
address: action.payload.addressData
};
}
case 'uploadImage': {
return {
...state,
uploadImage: action.payload
};
}
default:
return state;
}
};
export default addressReducer;
You need to spread the object state out otherwise there is never a reference to the state before the update.
The object spread syntax lets you use the spread ... operator to copy enumerable properties from one object to another in a more succinct way.
I am using multiple reducers in my project and then combining them with combineReducers() function and have all actions in single file. when i dispatch the action, it is returning me state values to undefined. I think It can't find out because of multiple reducerse. But when i use single reducer file. It is working fine. Can anyone please tell me what the issue.It is how i am combining the reducers.
const rootReducer = combineReducers({
isMobileReducer,
imageSliderReducer
})
and now passing to store, like below:
let store = createStore(rootReducer,applyMiddleware(thunk))
and in frontend how i am accessing state
const mapStateToProps = (state) => ({
images: state.images,
isMobile: state && state.isMobile
})
imageSliderReducer.js
import {
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from '../actions/actionTypes'
const initialState = {
images:[],
error:null
}
const imageSliderReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_IMAGES_BEGIN:
return {...state,error:null}
case FETCH_IMAGES_SUCCESS:
return {...state,images:action.payload.images}
case FETCH_IMAGES_FAILURE:
return {...state,error:action.payload.error,images:[]}
default:
return state
}
}
export default imageSliderReducer;
isMobileReducer.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
} from '../actions/actionTypes'
const initialState = {
isMenuOpen: null,
isMobile: false
}
const isMobileReducer = (state = initialState, action) => {
switch (action.type) {
case OPEN_MENU:
return {...state, isMenuOpen: true}
case CLOSE_MENU:
return {...state, isMenuOpen: false}
case SET_DEVICE_TYPE:
return {...state, isMobile: action.isMobile}
default:
return state
}
}
export default isMobileReducer;
actionCreator.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from './actionTypes'
export function openMenu(isMobile) {
return {
type: OPEN_MENU
}
}
export function closeMenu(isMobile) {
return {
type: CLOSE_MENU
}
}
export function setDeviceType (isMobile) {
return {
type: SET_DEVICE_TYPE,
isMobile: isMobile
}
}
export function fetchImages() {
return dispatch => {
dispatch(fetchImagesBegin());
return fetch("https://7344.rio.com/wp-json/customapi/homeslider")
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchImagesSuccess(json.posts));
return json.posts;
})
.catch(error => dispatch(fetchImagesFailure(error)));
};
}
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
export const fetchImagesBegin = () => ({
type: FETCH_IMAGES_BEGIN
});
export const fetchImagesSuccess = images => ({
type: FETCH_IMAGES_SUCCESS,
payload: { images }
});
export const fetchImagesFailure = error => ({
type: FETCH_IMAGES_FAILURE,
payload: { error }
});
Try using this:
const mapStateToProps = (state) => ({
images: state.imageSliderReducer.images,
isMobile: state.isMobileReducer.isMobile
})