Can't get the action.payload go to the state Redux Toolkit - javascript

So I'm new to React and Redux Toolkit, I've been trying to get some 'posts' from my localhost API, I do get the payload and it gets displayed in the Redux Dev Tools, nevertheless I can't get this payload to be put on the state.
My postSlice.js :
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import axios from "axios";
export const getPosts = createAsyncThunk("posts", async () => {
try {
const res = await axios({
method: "get",
url: `${process.env.REACT_APP_API_URL}api/post`,
withCredentials: true,
});
console.log(res.data);
return res.data;
} catch (err) {
return err.res.data;
}
});
const postsSlice = createSlice({
name: "posts",
initialState: {
posts: [],
loading: false,
error:"",
},
extrareducers: {
[getPosts.pending]: (state, action) => {
state.loading = true;
},
[getPosts.fulfilled]: (state, action) => {
console.log(action.payload);
state.loading = false;
state.posts = action.payload;
},
[getPosts.rejected]: (state, action) => {
state.loading = false;
state.posts = action.payload.message;
},
},
});
export default postsSlice.reducer;
Then I use the dispatch on a React Component
import { useDispatch } from "react-redux";
import { getPosts } from "../redux/features/postSlice";
const Thread = () => {
const [loadPost, setLoadPost] = useState(true);
const dispatch= useDispatch();
useEffect(() => {
if (loadPost ) {
dispatch(getPosts());
setLoadPost(false)
}
}, [loadPost, dispatch]);
return <div>Fil d'actualités</div>;
};
export default Thread;
Finally I get this on the State in Redux Dev Tool
posts(pin):[]
loading(pin): false
error(pin): ""
And this on the Action:
payload (pin): [{...}{...}{...}]
Also, through the pending, fulfilled and rejected states, loading won't change a bit, even if I pass it on true or false directly with VSCode nor the log I put on the fulfilled extra reducer, it's like the action doesn't affect the state at all, therefore I have the another reducer working fine with the async functions, any help would be much appreciated!
EDIT: My bad, i made a misspelling mistake, 'r' instead of 'R' in 'extraReducers' declaration, the kind of error you feel so dumb about

I think you should use extraRedcuer that way:
extraReducers: (builder) => {
builder.addCase(getPosts.pending, (state, action) => {
state.loading = true;
}),
builder.addCase(getPosts.fulfilled, (state, action) => {
console.log(action.payload);
state.loading = false;
state.posts = action.payload;
}),
builder.addCase(getPosts.rejected, (state, action) => {
state.loading = false;
state.posts = action.payload.message;
}),
},

Related

Redux not showing result

i need help with redux toolkit, i'm using redux to fetch one array of objects but this not happen bellow is my redux code and get api.
GET API
export const getProductsApi = async () => {
const response = await fetch(
`${gateway.url}/products`,
{
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
}
);
const data = await response.json();
return data;
}
MY REDUX ACTION
import {
getProductsPending,
getProductsSuccess,
getProductsFailed,
} from "../../slices/get-products";
import { getProductsApi } from "../../../api/get-products";
export const getProducts = () => async (dispatch: any) => {
dispatch(getProductsPending());
try {
const response = await getProductsApi();
const data = response.data;
console.log('products redux here', data);
dispatch(getProductsSuccess(data));
} catch (error) {
dispatch(getProductsFailed(error));
}
};
REDUX SLICE
const getProductsSlice = createSlice({
name: "getProducts",
initialState,
reducers: {
getProductsPending: (state) => {
state.isLoading = true;
state.error = "";
},
getProductsSuccess: (state, action: PayloadAction<Product[]>) => {
state.isLoading = false;
state.products = action.payload;
state.error = "";
},
getProductsFailed: (state, action) => {
state.isLoading = false;
state.error = action.payload.error;
state.products = [];
},
},
});
const { reducer, actions } = getProductsSlice;
export const { getProductsPending, getProductsSuccess, getProductsFailed } =
actions;
export default reducer;
REDUX STORE
import { configureStore } from "#reduxjs/toolkit";
import getProductsReducer from "../redux/slices/get-products";
const store = configureStore({
reducer: {
products: getProductsReducer,
},
});
store.subscribe(() => console.log(store.getState()));
export default store;
in my browser console when is to appear the data, data appear so
whit my products array empty, and i don't know where is my error because anothers redux i made, i make like this and work correctly.
I appreciate every help to solve my question.
using redux tookit

error when passing parameters to an async redux action

I am trying to create a scraping application using redux toolkit for learning purposes but the scraping process fails whenever I pass custom parameters in the dispatch statement but works correctly on passing default parameters in the thunk
My async thunk
export const loadData = createAsyncThunk(
"alldata/getdata",
async ({ pageNo, language }, thunkAPI) => {
const data = await fetch(
`http://localhost:5000/scrape?pageNo=${encodeURIComponent(
pageNo
)}&language=${encodeURIComponent(language)}`
);
const json = data.json();
return json;
}
);
My slice
const projectSlice = createSlice({
name: "allprojects",
state: {
projectState: [],
workingState: [],
isLoading: false,
hasError: false,
},
reducers: {
addProject: (state, action) => {
return state.workingState.push(action.payload);
},
removeProject: (state, action) => {
return state.workingState.filter(
(project) => project.id !== action.payload.id
);
},
},
extraReducers: {
[loadData.pending]: (state, action) => {
state.isLoading = true;
state.hasError = false;
},
[loadData.fulfilled]: (state, action) => {
const { json } = action.payload;
state.isLoading = false;
state.hasError = false;
},
[loadData.rejected]: (state, action) => {
state.isLoading = false;
state.hasError = true;
},
},
});
export const { addProject, removeProject } = projectSlice.actions;
export const { Projectreducer } = projectSlice.reducer;
export const selectAllPosts = (state) => state.allprojects.projectState;
Calling the async action
React.useEffect(() => {
console.log(dispatch(loadData(1, "ruby")));
}, []);
//url:https://github.com/search?p=undefined&q=language%3Aundefined
how do I solve this error
The async thunk arguments must be collected in one object:
dispatch(loadData({ pageNo: 1, language: "ruby" }))
See https://redux-toolkit.js.org/api/createAsyncThunk#payloadcreator

React | Redux Toolkit Shared State Undefined

I am creating a simple app to play with Redux ToolKit along react; however, I can see the object in the redux chrome tab, but unable to access it through components using react hooks.
My slice:
import {
createSlice,
createSelector,
createAsyncThunk,
} from "#reduxjs/toolkit";
const initialState = {
cryptoList: [],
loading: false,
hasErrors: false,
};
export const getCryptos = createAsyncThunk("cryptos/get", async (thunkAPI) => {
try {
const cryptosUrl =
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd";
let response = await fetch(cryptosUrl);
console.log(response);
return await response.json();
} catch (error) {
console.log(error);
}
});
const cryptoSlice = createSlice({
name: "cryptos",
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(getCryptos.pending, (state) => {
state.loading = true;
});
builder.addCase(getCryptos.fulfilled, (state, { payload }) => {
state.loading = false;
state.cryptoList = payload;
});
builder.addCase(getCryptos.rejected, (state, action) => {
state.loading = false;
state.hasErrors = action.error.message;
});
},
});
export const selectCryptos = createSelector(
(state) => ({
cryptoList: state.cryptoList,
loading: state.loading,
}),
(state) => state
);
export default cryptoSlice;
My component:
import React, { useEffect } from "react";
import { getCryptos, selectCryptos } from "./cryptoSlice";
import { useSelector, useDispatch } from "react-redux";
const CryptoComponent = () => {
const dispatch = useDispatch();
const { cryptoList, loading, hasErrors } = useSelector(selectCryptos);
useEffect(() => {
dispatch(getCryptos());
}, [dispatch]);
const renderCrypto = () => {
if (loading) return <p>Loading Crypto...</p>;
if (hasErrors) return <p>Error loading news...</p>;
if (cryptoList) {
return cryptoList.data.map((crypto) => <p> {crypto.id}</p>);
}
};
return (
<div className="container">
<div className="row">CryptoComponent: {renderCrypto()}</div>
</div>
);
};
export default CryptoComponent;
All constructed values from the state: cryptoList, loading, hasErrors, seem to be undefined at the component level.
Any suggestions are appreciated!
Have you tried using the following createSelector code:
export const selectCryptos = createSelector(
(state) => state,
(state) => ({
cryptoList: state.cryptoList,
loading: state.loading,
})
);
As per documentation state should be the first parameter:
https://redux.js.org/usage/deriving-data-selectors

Migrating from Redux to Redux toolkit

I'm slowly migrating over from Redux to Redux toolkit. I'm still pretty new but I have this login action function. How can I translate old function below do I need createAsyncThunk to achieve this?
export const login = (email, password) => (dispatch) => {
dispatch(requestLogin());
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((user) => {
dispatch(responseLogin(user));
})
.catch((error) => {
dispatch(loginError());
});
};
and my auth slice looks something like this:
const authSlice = createSlice({
name: "authSlice",
initialState: {
isLoggingIn: false,
isLoggingOut: false,
isVerifying: false,
loginError: false,
logoutError: false,
isAuthenticated: false,
user: {},
},
reducers: {
signInWithEmail: (state, action) => {
const { email, password } = action.payload;
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((response) => {
const {
uid,
email,
emailVerified,
phoneNumber,
password,
displayName,
photoURL,
} = response.user;
})
.catch((error) => {
console.log(error);
});
},
},
extraReducers: {},
});
Lets create a productSlice.js
import { createSlice,createSelector,PayloadAction,createAsyncThunk,} from "#reduxjs/toolkit";
export const fetchProducts = createAsyncThunk(
"products/fetchProducts", async (_, thunkAPI) => {
try {
const response = await fetch(`url`); //where you want to fetch data
return await response.json();
} catch (error) {
return thunkAPI.rejectWithValue({ error: error.message });
}
});
const productsSlice = createSlice({
name: "products",
initialState: {
products: [],
loading: "idle",
error: "",
},
reducers: {},
extraReducers: (builder) => {
builder.addCase(fetchProducts.pending, (state) => {
state. products = [];
state.loading = "loading";
});
builder.addCase(
fetchProducts.fulfilled, (state, { payload }) => {
state. products = payload;
state.loading = "loaded";
});
builder.addCase(
fetchProducts.rejected,(state, action) => {
state.loading = "error";
state.error = action.error.message;
});
}
});
export const selectProducts = createSelector(
(state) => ({
products: state.products,
loading: state.products.loading,
}), (state) => state
);
export default productsSlice;
In your store.js add productsSlice: productsSlice.reducer in out store reducer.
Then for using in component add those code ... I'm also prefer to use hook
import { useSelector, useDispatch } from "react-redux";
import { fetchProducts,selectProducts,} from "path/productSlice.js";
Then Last part calling those method inside your competent like this
const dispatch = useDispatch();
const { products } = useSelector(selectProducts);
React.useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
And Finally, you can access data as products in your component.
The reducer you showed is very wrong. Reducers must never do anything async!
You don't need createAsyncThunk, but if you want to use it, it'd be like this:
export const login = createAsyncThunk(
'login',
({email, password}) => firebase.auth().signInWithEmailAndPassword(email, password)
);
const authSlice = createSlice({
name: "authSlice",
initialState: {
isLoggingIn: false,
isLoggingOut: false,
isVerifying: false,
loginError: false,
logoutError: false,
isAuthenticated: false,
user: {},
},
reducers: {
/* any other state updates here */
},
extraReducers: (builder) => {
builder.addCase(login.pending, (state, action) => {
// mark something as loading here
}
builder.addCase(login.fulfilled, (state, action) => {
// mark request as complete and save results
}
}
});
Note that createAsyncThunk only allows one argument to be passed to the thunk action creator, so it now must be an object with both fields instead of separate arguments.

SetAll from CreateEntityAdapter do not set the state with react redux toolkit

I am trying to use Redux Toolkit in my new website and I have a problem using the createEntityAdapter.
I am fetching some data from my database but my state is never updated with the data fetched and I do not understand why.
My slice and fetch functions:
export const getTransports = createAsyncThunk('marketplace/transports/getTransports', async email => {
const response = await axios.get(`${API_URL}/transport/published/company/${email}/notActive`);
console.log('response', response);
const data = await response.data;
console.log('DATA', data);
return data;
});
const transportsAdapter = createEntityAdapter({});
export const { selectAll: selectTransports, selectById: selectTransportById } = transportsAdapter.getSelectors(
state => state.marketplace.transports
);
const transportsSlice = createSlice({
name: 'marketplace/transports',
initialState: transportsAdapter.getInitialState({
searchText: ''
}),
reducers: {
setTransportsSearchText: {
reducer: (state, action) => {
state.searchText = action.payload;
},
prepare: event => ({ payload: event.target.value || '' })
},
extraReducers: {
[getTransports.fulfilled]: transportsAdapter.setAll
}
}
});
export const { setTransportsSearchText } = transportsSlice.actions;
export default transportsSlice.reducer;
The data fetch is working well and the state between the request and de fullfilled looks like working as it should be, but as you can see in the console, the transports state is never updated.
Redux Logger
I do not understand why is not working the setAll function from the transportsAdapter.
The entities that are being retrieved have and id and the entity information, so it should work correctly but it does not.
I hope you can help me.
Thank you very much.
I was facing the same issue following along the Redux Essentials Tutorial.
I fixed it by specifying the parameters to the function setAll() and using the builder callback approach.
const transportsSlice = createSlice({
name: 'marketplace/transports',
initialState: transportsAdapter.getInitialState({
searchText: ''
}),
reducers: {
setTransportsSearchText: {
reducer: (state, action) => {
state.searchText = action.payload;
},
prepare: event => ({ payload: event.target.value || '' })
},
extraReducers: (builder) => {
builder.addCase(getTransports.fulfilled, (state, action) => {
transportsAdapter.setAll(state, action.payload);
});
},
});

Categories

Resources