Redux State is Repeated on Every GET Request - reactjs

I am mapping through an array where I am taking every item in the array and calling a GET request on each item. Then I am pushing them all together in my redux state. The issue is that every time I reload the information is repeated. I am thinking that the way to solve this issue is to clean out my redux store everytime that the request is run however, I do not want to wipe everything, just the photos portion in this case.
momentcontent.js:
componentDidMount () {
this.props.photos.map(photo => {
this.props.fetchPhoto(this.props.token, photo)}
)
}
index.js (actions):
export const fetchPhoto = (token, photo) => dispatch => {
console.log('right token')
console.log(token);
fetch(photo, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Token ${token}`,
}
})
.then(res => res.json())
.then(parsedRes => {
console.log('photo data')
console.log(parsedRes)
dispatch(getPhoto(parsedRes))
})
}
export const getPhoto = (photo) => {
console.log('RES')
console.log(photo)
return {
type: GET_PHOTO,
photo: photo
}
}
photo.js:
import {
GET_PHOTO
} from '../actions';
const initialState = {
photo: []
}
const photoReducer = (state = initialState, action) => {
switch(action.type) {
case GET_PHOTO:
return {
...state,
photo: [...state.photo, action.photo]
}
default:
return state;
}
}
export default photoReducer
my console (I should have 9 items in the array, I have 27 here):

Rather than clearing the redux store photos object and re-adding, you can check if the photo already exists in the store or not.
Assuming that your state contains a photo array, action contains photo object and photo (the image url instance) is a unique object
Therefore you can modify your reducer as
case GET_PHOTO:
return state.photo.some(( { photo } ) => photo === action.photo.photo)
? state
: [...state.photo, action.photo];

Related

How to get data from an API using redux?

I am requesting an API using redux and saga
I the request is working fine I am able to get API returned data in the reducer, but I am not able to get that data in the home.js I am new to redux please help me.
in my home.js this is how I am making a call
const fetchSessionData = () => {
dispatch(
fetchSession({
token: token
})
)
}
action.js
export const fetchSession = data => {
return {
type: Action.SESSION_DATA,
payload: {data},
};
};
this is reducer file
export const SessionData = (state = sessionState, action) => {
console.log('inside session reducer', JSON.stringify(action));
switch (action.type) {
case Action.SESSION_FETCH_SUCCESS:
return {
...state,
isLoading: false,
};
case Action.SESSION_FETCH_ERROR:
return {
...state,
sagaerror: action.error,
isLoading: false,
};
case Action.SESSION_DATA:
return {
...state,
isLoading: true,
};
default:
return state;
}
};
and this is the api
export function fetchSessionData(payload) {
return fetch(`${url}/session/`, {
method: 'GET',
headers: {
Authorization: `Bearer ${payload.token}`,
Accept: 'application/json',
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(res => {
return res;
})
.catch(error => {
throw error;
});
}
how can I get the returning data from api in home.js?
Looks like you are not storing back the response from saga.
Please have an action for storing the response into your reducer.you may use
yield put(storeactionname(payload received from api reponse);
in your saga method and in reducer your action.payload should be stored into a state variable
and in your component you can use useSelector like below
const { yourvariableNameInStateInReducer } =
useSelector((state) => state.yourreducername);
As you say you will able to get data to reducer. It's then fine in that section. In the component you need to select stored data from the store. If you are using functional component you can use useSelector hook in react-redux. If you are using class component then you need to use connect function, you need to pass mapStateToProps and mapDispatchToProps arguments to the connect function. Refer https://react-redux.js.org/api/connect

How to only fetch the required data according to a boolean value in Redux Toolkit?

i have a query regarding redux toolkit. I want to get the list of array on the click of a checkbox. the array objects has a field called "verified " which is either true or false. According to that, Onclick of the check box i'd like to get all the objects which have the verified value set to true.
Also there isn't any end point called "verified " Which I can pass in the url to fetch a list of only verified array of objects which is want i want to achieve.
array structure looks like this =>
{_id(pin):"61bc940989b38d9bc53832e3"
venture(pin):"xyz"
rating(pin):2.3
promotion(pin):0
verified(pin):false
},
{_id(pin):"sjkdfkla38d9bc53832e3"
venture(pin):"xyz"
rating(pin):2.3
promotion(pin):0
verified(pin):true
},
{_id(pin):"blahbdsfasd3"
venture(pin):"xyz"
rating(pin):2.3
promotion(pin):0
verified(pin):true
},
below is my reducer and action.
Action = >
// get all Media Verified Cards
export const getVerifiedCards = createAsyncThunk(
'verifiedmedia/getall',
async () => {
try {
const header = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${Token_Media_Seller}`,
ClientId: `Bearer ${ClientId}`
}
}
const response = await axiosInstance.get(
`/media/?token=${Token_Media_Seller}&client_id=${ClientId}`,
header
)
console.log(response)
return response.data
} catch (error) {
throw error
}
}
)
Reducer=>
import { createSlice } from '#reduxjs/toolkit'
import { getMediaCards } from '../actions/mediacards'
const initialState = {
mediaCards: []
}
export const mediacardSlice = createSlice({
name: 'medialist',
initialState: initialState,
reducers: {},
extraReducers: {
[getMediaCards.fulfilled.type]: (state, { payload }) => {
return {
...state,
mediaCards: payload.data
}
}
}
})
My checkbox component =>
All the exports =>
const dispatch = useAppDispatch()
const selector = useAppSelector(state => state.mediacard.mediaCards) //all the items
//onclick function and the action which i want to make to get the verified values
const sortVerified = () => {
dispatch(getVerifiedCards())
console.log('action dispatched')}
JSX=>
<div className=''>
<input
type='checkbox'
value={'checked'}
onClick={sortVerified}
/>
</div>
pls help ive been trying differrent methods but i dont what to do :(
well there was no true value so when ever i tried to filter out the array it gave nothing as the output so yeah...

Access to API using Redux

I have a react-redux app. I need to call API and used it in my component. The app is called with fetch in function in utills.
All functions are group and export like this:
export const sportTeam = {
getBasketballTeam,
getBasketballTeamById,
}
function getBasketballTeam() {
let token = store.getState().UserReducer.token;
fetch(
actions.GET_BASKETBALLTEAM,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
}
)
.then((res) => {
if (res.status == 200 ) {
return res.json();
}
})
.then((response) => {
console.log(response);
})
.catch((err) => {
console.log(err);
});
}
getBasketballTeam contains an array of objects.
How can I get getBasketballTeam and used it in the component in the view to returning the list with this data?
You don't want your getBasketballTeam function to access the store directly through store.getState().
What you want is a "thunk" action creator that gets the store instance as an argument when you dispatch it.
The flow that you want is this:
Component continuously listens to the basketball team state with useSelector (or connect).
Component mounts.
Component dispatches a getBasketballTeam action.
Action fetches data from the API.
Reducer saves data from the action to the state.
State updates.
Component re-renders with the new data from state.
The easiest way to do this is with the createAsyncThunk function from Redux Toolkit. This helper handles all errors by dispatching a separate error action. Try something like this:
Action:
export const fetchBasketballTeam = createAsyncThunk(
"team/fetchBasketballTeam",
async (_, thunkAPI) => {
const token = thunkAPI.getState().user.token;
if ( ! token ) {
throw new Error("Missing access token.");
}
const res = await fetch(actions.GET_BASKETBALLTEAM, {
method: "GET",
headers: { Authorization: `Bearer ${token}` }
});
if (res.status !== 200) {
throw new Error("Invalid response");
}
// what you return is the payload of the fulfilled action
return res.json();
}
);
Reducer:
const initialState = {
status: "idle",
data: null
};
export const teamReducer = createReducer(initialState, (builder) =>
builder
.addCase(fetchBasketballTeam.pending, (state) => {
state.status = "pending";
})
.addCase(fetchBasketballTeam.fulfilled, (state, action) => {
state.status = "fulfilled";
delete state.error;
state.data = action.payload;
})
.addCase(fetchBasketballTeam.rejected, (state, action) => {
state.status = "rejected";
state.error = action.error;
})
);
Store:
export const store = configureStore({
reducer: {
team: teamReducer,
user: userReducer,
}
});
Component:
export const BasketballTeam = () => {
const { data, error, status } = useSelector((state) => state.team);
const dispatch = useDispatch();
useEffect(
() => {
dispatch(fetchBasketballTeam());
},
// run once on mount
// or better: take the token as an argument and re-run if token changes
[dispatch]
);
if (status === "pending") {
return <SomeLoadingComponent />;
}
if (!data) {
return <SomeErrorComponent />;
}
// if we are here then we definitely have data
return <div>{/* do something with data */}</div>;
};
After you get response you need to do the following things
call dispatch function to store the data received in REDUX state.
Now when you have data in redux state, you can use useSelector() to get that state and make use of it in your jsx file.

How do I update Redux store with POST response?

I have an application that is using React, Redux (Redux Thunk). I having an issue updating the state in the reducer after a fetch post inserts into a table.
I am trying to dispatch an action and pass some information from the action to the reducer but not able to do so. I am specifically trying to pass the fetch response into the dispatch. I have a key named res within my dispatch. I set it to a value of data but I believe this value of data is undefined.
export function insertSearchTerm(searchTerm) {
console.log('C')
return (dispatch) => {
fetch('http://localhost:3001/api/v1/searches?searchterm='+ searchTerm, {
headers: {
'Content-Type':'application/json', //headers - tells y9ou that it is json
},
method:'POST',
body: JSON.stringify(searchTerm) //stringifies searchTerm
}).then(res => console.log('Inside insertSearch Term resp', res.json()))
.then(data => {
dispatch({
type:'INSERT_SEARCH_TERM',
searchTerm: searchTerm,
res : data
})
}
)
}
console.log('E')
}
export default function allSearchTermsReducer(state = {allSearchTerms: []}, action) {
switch (action.type) {
case 'ALL_SEARCHES':
console.log("Allsearch reducer",action.payload);
return {...state, allSearchTerms: action.payload}
case 'INSERT_SEARCH_TERM':
console.log('insert search term action', action)
return {
...state,
allSearchTerms: [...state.allSearchTerms, action.id, action.searchTerm, action.created_at] }
default:
return state
}
};
In your action-creator, for the first .then block you are returning a console.log() not the data itself. So there's no data to dispatch in the proceeding .then block. Should be updated to:
export function insertSearchTerm(searchTerm) {
console.log('C')
return (dispatch) => {
fetch('http://localhost:3001/api/v1/searches?searchterm='+ searchTerm, {
headers: {
'Content-Type':'application/json', //headers - tells y9ou that it is json
},
method:'POST',
body: JSON.stringify(searchTerm) //stringifies searchTerm
}).then(res => res.json())
.then(data => {
dispatch({
type:'INSERT_SEARCH_TERM',
searchTerm: searchTerm,
res : data
})
}
)
}
console.log('E')
}

Can not listener state is changed when use applyMiddleware inside createStore()

I'm using react , react-redux , redux . and then I had a problem .
When I use :
const store = createStore(reducers);
store.subscribe(() => {
console.log(getState());
});
=> Result : I can see value in getState() be changed when i use dispatch some action to update/get/...etc STATE . BUT if I use applyMiddleware . I won't see value is changed in State when has any action
import indexService from './dashboard/services/services.jsx';
const store = createStore(reducers, applyMiddleware(indexService));
store.dispatch({ type: 'DASHBOARD_GET_CURRENT_DEALS' });
This is indexService component
import { config } from '../../helps.jsx';
const indexService = store => next => action => {
switch (action.type) {
case 'DASHBOARD_GET_CURRENT_DEALS':
fetch(config.homeUrl + '/data/_curentDeals.json', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
}).then(function (response) { return response.json() }).then(function (json) {
next({
type: 'DASHBOARD_GET_CURRENT_DEALS',
json
})
}).catch(function (error) { console.log('erros', error); });
break;
default:
break;
}
};
export default indexService;
Thanks your helps;
applyMiddleware should be the third argument in createStore
const store = createStore(reducers, {}, applyMiddleware(indexService));
CreateStore takes the following arguments
createStore(reducer, [preloadedState], [enhancer])
Arguments
reducer (Function): A reducing function that returns the next state tree, given the current state tree and an action to handle.
[preloadedState] (any): The initial state. You may optionally specify it to hydrate the state from the server in universal apps, or to restore a previously serialized user session. If you produced reducer with combineReducers, this must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your reducer can understand.
[enhancer] (Function): The store enhancer. You may optionally specify it to enhance the store with third-party capabilities such as middleware, time travel, persistence, etc. The only store enhancer that ships with Redux is applyMiddleware().
Apart from this you are not retuning the action form the service and also call next on action
import { config } from '../../helps.jsx';
const indexService = store => next => action => {
next(action);
switch (action.type) {
case 'DASHBOARD_GET_CURRENT_DEALS':
fetch(config.homeUrl + '/data/_curentDeals.json', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
}).then(function (response) { return response.json() }).then(function (json) {
return next({
type: 'DASHBOARD_GET_CURRENT_DEALS',
json
})
}).catch(function (error) { console.log('erros', error); });
break;
default:
break;
}
};
export default indexService;

Resources