I am trying to extend my frontend code with another redux call but the data is not appearing in store.
Here is store definition
const store = configureStore({
reducer: {
login: loginSlice.reducer,
cart: cartSlice.reducer,
product: productSlice.reducer,
notification: notificationSlice.reducer
}
});
Here is a slice
const productSlice = createSlice({
name: 'product',
initialState: {
products: []
},
reducers: {
replaceData(state,action) {
console.log(action)
state.products = action.payload.products;
}
}
});
export const productActions = productSlice.actions
export default productSlice
And action
export const fetchProducts = () => {
return async (dispatch) => {
const fetchHandler = async () => {
const resp = await fetch("https://shoppingcart-a62bb-default-rtdb.europe-west1.firebasedatabase.app/products.json")
const data = await resp.json();
}
try {
const productData = await fetchHandler();
dispatch(productActions.replaceData(productData))
} catch (err) {
dispatch(notificationActions.showNotification({
open: true,
message: "Error reading product data",
type: 'error'
}));
}
}
}
That's what I call in APP.js
useEffect(()=>{
dispatch(fetchCartData())
dispatch(fetchProducts())
},[dispatch]);
Here I read data from store in component
let respProducts = useSelector(state => state.product.products);
console.log(respProducts)
The problem is that fetch in action works,but payload in dispatch empty and no data in useSelector.
I really don't get what's wrong as similar code in the same app works.
Your fetchHandler is missing a return statement.
const fetchHandler = async () => {
const resp = await fetch("https://shoppingcart-a62bb-default-rtdb.europe-west1.firebasedatabase.app/products.json")
const data = await resp.json();
return data
}
use 'useReduxSelector' instead of 'useSelector'
Related
I have a problem, I'm looking for a solution, please help.
I am building a React application and using Redux thunk to call the data from the backend
This is the code inside the useEffect
let [events, setEvents] = useState([]);
let [featured, setFeatured] = useState([]);
let [categories, setCategories] = useState([]);
let [interests, setInterests] = useState([]);
useEffect(() => {
let params = new FormData();
if (user) {
params.append('phone_number', user.phone_num);
}
dispatch(
getHomeData(params, json => {
if (json.success) {
console.log(data);
let {data} = json;
setEvents(data?.events);
setFeatured(data?.featured);
setCategories(data?.categories);
setInterests(data?.interests);
if (user) {
dispatch(setNotificationCount(data?.notifications));
}
}
}),
);
}, []);
redux action
import {AppConstant, httpHelperApp} from '../../common';
import {
NOTIFICATION_SET,
HOME_DATA_PENDING,
HOME_DATA_FULFILLED,
HOME_DATA_REJECTED,
} from '../constant';
let HomeApi = 'api/adjusted/essentials.php';
export let getHomeData = (payload, callBack) => {
return async dispatch => {
dispatch({type: HOME_DATA_PENDING});
let data = await httpHelperApp.postApi(payload, HomeApi);
if (data.success) {
dispatch({type: HOME_DATA_FULFILLED, payload: data});
} else {
dispatch({type: HOME_DATA_REJECTED});
}
};
};
export let setNotificationCount = payload => {
return {
type: NOTIFICATION_SET,
payload,
};
};
redux-reducer
let initialState = {
notificationCount: 0,
};
export const HomeReducer = (state = initialState, action) => {
const {type, payload} = action;
switch (type) {
case NOTIFICATION_SET:
return {...state, notificationCount: payload};
default:
return state;
}
};
The problem is that I get an infinite loop and the useEffect keeps working but it stops when I stop the dispatch notification dispatch(setNotificationCount(data?.notifications)) or stop any update to state redux.what did I do wrong please help.
component where I am using the state data
const { contentTitles: ContentTitles } = useSelector((state) => state);
const dispatch = useDispatch();
useEffect(() => {
const fetchData = async () => {
const response = await dispatch(getContentTitles()).unwrap();
};
fetchData();
}, [ContentTitles]);
slice
const contentTitles = JSON.parse(localStorage.getItem("contentTitles"));
export const getContentTitles = createAsyncThunk("contenttitles/getContenttitles", async (thunkAPI) => {
try{
const response = await contentitleService.getContenttitles();
return { contentTitles: response };
} catch (error) {
const message =
(error.response &&
error.response.responsedata &&
error.response.responsedata.message) ||
error.message ||
error.toString();
thunkAPI.dispatch(setMessage(message));
return thunkAPI.rejectWithValue();
}
});
const initialState = contentTitles ? contentTitles : null
const contenttitleSlice = createSlice({
name: "contenttitles",
initialState,
reducers: (state, action) => {
state.contentTitles = action.payload.contentTitles;
}
});
const { reducer } = contenttitleSlice;
export default reducer;
Can anyone tell me that why my data is not getting set to the redux? I am new to the redux and asyncthunk. I can't find the reason of not getting my redux state updated.
You have to define an extra actions (extraReducers) for this. Since your codebase is not clear to me, I will use a different example to explain it to you.
// First, create the thunk
const fetchUserById = createAsyncThunk(
'users/fetchByIdStatus',
async (userId: number, thunkAPI) => {
const response = await userAPI.fetchById(userId)
return response.data
}
)
const initialState = {
user: null
}
const usersSlice = createSlice({
name: 'users',
initialState,
reducers: {
// Define your other actions here
},
extraReducers: (builder) => {
// Add reducers for additional action types here, and handle loading state as needed
builder.addCase(fetchUserById.fulfilled, (state, action) => {
// Add user to the state array
state.user = action.payload;
})
},
})
As you can see here, after the request completed, it will either be a success or error response. You have to define extra reducers to catch this. Above example shows a successful scenario. But you can define extra actions for following phases as well.
pending: 'users/requestStatus/pending'
fulfilled: 'users/requestStatus/fulfilled'
rejected: 'users/requestStatus/rejected'
const initialState = contentTitles ? {contentTitles} : {contentTitles: null}
const contenttitleSlice = createSlice({
name: "contenttitles",
initialState,
extraReducers: {
[getContentTitles.fulfilled]: (state, action) => {
state.contentTitles = action.payload.contentTitles
},
},
});
Yes, the extraReducers were missing. The above code of adding extraReducers in my specific scenario solved the problem.
I need help. I don't understand why my dispatch action doesn't work. I've redux store currency list and current currency.
My reducer:
export const currencyReducer = (
state: typeState = initialState,
action: TypeActionCurrency
): typeState => {
switch (action.type) {
case types.CURRENCY_FILL_LIST:
return { ...state, list: action.payload }
case types.CURRENCY_SET_CURRENT:
return {
...state,
current:
state.list.find(currency => currency._id === action.payload) ||
({} as ICurrency),
}
default:
return state
}
}
My actions:
export const setCurrencyList = (currencies: ICurrency[]) => ({
type: types.CURRENCY_FILL_LIST,
payload: currencies,
})
export const setCurrentCurrency = (_id: string) => ({
type: types.CURRENCY_SET_CURRENT,
payload: _id,
})
My useEffect:
useEffect(() => {
if (!list.length) {
const fetchCurrencies = async () => {
try {
const data = await $apiClient<ICurrency[]>({ url: '/currencies' })
dispatch(setCurrencyList(data))
if (!current._id) dispatch(setCurrentCurrency(data[0]._id))
} catch (error) {
console.log(error)
}
}
fetchCurrencies()
}
}, [])
I want make request when load page and write currency list to Redux store, if we don't have current currency we write default currency from data.
There is one more strange thing, my redux extension shows that the state has changed, but when I receive it via the log or useSelector, it is empty
enter image description here
Thanks!
I am not 100% sure but it should work.
const [loader, setLoader] = useState(false);
const list = useSelector(state => state.list)
useEffect(() => {
if (!list.length) {
const fetchCurrencies = async () => {
try {
setLoader(true)
const data = await $apiClient<ICurrency[]>({ url: '/currencies' })
dispatch(setCurrencyList(data))
if (!current._id) dispatch(setCurrentCurrency(data[0]._id))
} catch (error) {
console.log(error)
} finally {
setLoader(false)
}
}
fetchCurrencies()
}
}, [])
useEffect(() => {
console.log(list);
}, [loader])
I'm trying to implement CRUD and retreive all data and put it into a table, so the console log return undefined, so I called the payload and it's not an array and I think that's the issue maybe. I'm using redux Thunk hooks. please can someone help me to solve it
here is the code bellow :
Component.jsx
import { retrieveCars } from '../action/cars.action'
const cars = useSelector(state => state.cars);
const dispatch = useDispatch();
useEffect(() => {
dispatch(retrieveCars());
});
cars.action.js
export const retrieveCars = () => async (dispatch) => {
try {
const res = await DataService.getAll();
dispatch({
type: RETRIEVE_CARS,
payload: res.data,
});
} catch (err) {
console.log(err);
}
};
Car Reducer:
const initialState = [];
function carReducer(cars = initialState, action) {
const { type, payload } = action;
switch (type) {
case CREATE_CAR:
return [...cars, payload];
case RETRIEVE_CARS:
return payload;
}
Car actions :
export const retrieveCars = () => async (dispatch) => {
try {
const res = await DataService.getAll();
dispatch({
type: RETRIEVE_CARS,
payload: res.data,
});
} catch (err) {
console.log(err);
}
};
The payload that I get isn't an array
It seems the payload you get is an array of objects if the screenshot above represents the payload.
Maybe you could try to refactor your code.
useEffect(async() => {
const res = await DataService.getAll();
dispatch(retrieveCars(res.data));
}, []);
Your action retriveCars could looks like this:
const retrieveCars = (payload) => {
({
type: RETRIEVE_CARS,
payload
});
};
I am not sure do you use Redux Thunk middleware in the code.
I only want to redirect if the post request is success on submit/onKeyDown using history.push(). The trouble is the function for my post request is in Redux Thunk.
While there is a way to create custom history and import history in redux and use history.push() in action/thunk I don't want to do that. I would like to keep history.push() in my React component. How can I do this?
My post function in my react component
const [patientName, setPatientName] = useState('');
const handlePatientNameChange = ({ target: { name, value } }) => {
setPatientName({ [name]: value });
};
const onKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
dispatch(postRoomPatient(patientName, roomId));
// if dispatch is success history.push('/home')
}
};
// if error true - post is fail otherwise success.
const roomPatientError = useSelector((state) => state.roomPatients[roomId] && state.roomPatients[roomId].error);
my redux reducer/action
const roomPatientsSlice = createSlice({
name: 'roomPatients',
initialState: initialState,
reducers: {
setPatientSuccess: (state, action) => {
const { patientName, roomId } = action.payload;
const prevState = state[roomId];
state[roomId] = {
...prevState,
patientName: patientName,
error: false,
};
},
}
});
export const postRoomPatient = (patientName, roomId) => async dispatch => {
try {
const response = await axios.post('/patient/add', patientName, {
headers: { 'Content-Type': 'text/plain' }
});
const patientName = await response.data;
dispatch(setPatientSuccess({ patientName, roomId }));
// if success I want to history.push (`/home`) but do it in my React component
}
catch (err) {
console.log(err)
}
};