Axios get in stock items - reactjs

I am trying to filter products whether it is available or not.
Not sure how to pass an axios request with ">" logic.
I've started to create an Action
export const listProductAvailable = () => async (dispatch) => {
dispatch({
type: PRODUCT_AVAILABLE_LIST_REQUEST,
});
try {
const { data } = await Axios.get(`/api/products?countInStock>0`);
dispatch({ type: PRODUCT_AVAILABLE_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({ type: PRODUCT_AVAILABLE_LIST_FAIL, payload: error.message });
}
};
But I don't think that such a request is possible.
const { data } = await Axios.get(/api/products?countInStock>0);
Also, I don't see myself changing my Product Model creating an isAvailable boolean field as it would be redundant with countInStock =0 or not.

Related

Axios calls with React : best practises

i want to know if there is some clean code or update to make it on my code, because i think i repeat the same code on every actions on my redux, my question is how can I avoid calling axios on my actions files ?
Please take a look on my code here :
export const SignInType = (host, lang) => async (dispatch) => {
try {
dispatch({
type: USER_LOGIN_SIGNINTYPE_REQUEST,
});
const { data } = await axios.get(
`/${lang}/data?host=${host}`
);
console.log({ data });
dispatch({
type: USER_LOGIN_SIGNINTYPE_SUCCESS,
payload: data,
});
dispatch({
type: USER_LOGIN_CLEAR_ERROR,
});
} catch (err) {
dispatch({
type: USER_LOGIN_SIGNINTYPE_FAIL,
payload: err,
});
}
};
I Really want to delete the Axios name from my actions file and make it on a separate file, but how can i do this ?
Thank you
We can suggest but there's no correct answer to this, initially any redundant lines of code can be abstracted, so in order to make things a little bit easier, we need to abstract the obvious and add the meaningful, e.g:
abstract the way you write action creators:
const actionComposer = (options) => (...args) => async dispatch => {
const modifiedDispatch = (type, payload) => dispatch({ type, payload });
const { action, onSuccess, onFailed } = options(modifiedDispatch);
try {
if (action) {
const res = await action(...args)
onSuccess(res);
}
} catch (err) {
onFailed(err)
}
}
then your code can look like this:
export const SignInType = actionComposer((dispatch)=> {
return {
action: async (host, lang) => {
dispatch(USER_LOGIN_SIGNINTYPE_REQUEST);
const { data } = await axios.get(`/${lang}/data?host=${host}`);
return data;
},
onSuccess: (res) => {
dispatch(USER_LOGIN_SIGNINTYPE_SUCCESS, data);
dispatch(USER_LOGIN_CLEAR_ERROR);
},
onFailed: (err) => {
dispatch(USER_LOGIN_CLEAR_ERROR, err.message)
}
}
})
Redux Toolkit already has a createAsyncThunk API that does all the work of defining the action types and dispatching them for you. You should use that.
Alternately, you can use our RTK Query data fetching and caching library, which will eliminate the need to write any data fetching logic yourself.

React/Redux: How to async or something else?

Hello Everyone,
need your help today with filtering in Redux...
I have filter (you can see on a picture) with several inputs (filters) for my search.
In order to receive Fleet information (filter) I need to pass an "ID" form Client...
const clientChange = (event) => {
const client = event.target.value;
const client_id = client.id;
dispatch({ type: "CLIENT_LIST_SELECTION", payload: client_id });
getFleetFilter();
};
That's my function clientChange in Form.js
const client_id = useSelector((state) => state.client.selection);
const getFleetFilter = async () => {
dispatch({ type: "FLEET_LIST_REQUEST" });
try {
let res = await getFleet(token, client_id);
let data = res.data.data
dispatch({ type: "FLEET_LIST_LOAD", payload: data });
} catch (err) {
if (err) {
console.log("Error Fleet Data");
console.log(err);
};
};
};
That's my function getFleetFilter in Search.js
Problem: I have undefined client_id in API string, because, function getFleetFilter getting called quicker, than client_id getting stored in Redux!
Question: How can I avoid this keeping using Redux here ?
Thank you!
You can use the useEffect callback for this like so:
const client_id = useSelector((state) => state.client.selection);
useEffect(() => {
if (client_id) {
getFleetFilter();
}
}, [client_id]);
const clientChange = (event) => {
const client = event.target.value;
const client_id = client.id;
dispatch({ type: "CLIENT_LIST_SELECTION", payload: client_id });
};
const getFleetFilter = async () => {
dispatch({ type: "FLEET_LIST_REQUEST" });
try {
let res = await getFleet(token, client_id);
let data = res.data.data
dispatch({ type: "FLEET_LIST_LOAD", payload: data });
} catch (err) {
if (err) {
console.log("Error Fleet Data");
console.log(err);
};
};
};

How to make dispatches synchronous

I have an the following function that is executed on button click:-
const modelClick = async(modelcategory, modelname)=>{
const curr_model = allModels.filter(model => model.model === modelname && model.version === version)
console.log("curr_model= ", curr_model[0]);
await dispatch(setModel(curr_model[0]))
await dispatch(getModelsOfType(curr_model[0]['model category']))
console.log("models=", models);
let temp;
temp = models.filter(model => model.modelname === curr_model[0]['model_type'])
console.log("temp inside modelClick= ", temp);
}
dispatch(getModelsOfType(curr_model[0]['model category'])) : This function queries the dynamodb and update the global redux state 'models'. I then want to filter the models based on type.
THE ISSUE i am facing is that the code below the dispatch gets executed before the state gets updated. It gives an error saying models is undefined. I want to run it synchronously so that the filter line gets executed only after models is updated. How can that be achieved ?
Here is the action creater function:-
export const getModelsOfType=(modeltype)=> async(dispatch) => {
dispatch({
type: GET_MODELS_OF_TYPE_REQUEST
})
let params = {
model_type: modeltype
}
axios
.post(`${BACKEND_URL}get-models`, params, {
headers: {
"Content-Type": "application/json",
},
})
.then((res)=>{
console.log("DYNAMO DB RESULT= ", res.data.Items)
dispatch({
type: GET_MODELS_OF_TYPE_SUCCESS,
payload: res.data.Items
})
})
.catch((err) => {
console.log("err >>", err);
dispatch({
type: GET_MODELS_OF_TYPE_FAIL
})
});
}
Instead of dispatching the action in the component. what you can do is dispatch the second action inside the first actions then block.
export const setModel=(your arguments)=> async(dispatch) => {
dispatch({
type: ACTION_REQUEST
})
axios
.post(// make API call)
.then((res)=>{
dispatch({
type: ACTION_SUCCESS,
payload: res
})
// now dispatch the second action here .
dispatch(getModelsOfType(your arguments))
})
.catch((err) => {
console.log("err >>", err);
dispatch({
type: ACTION_FAILURE
})
});
}

Fetch array of url's

I'm working with redux and I am trying to fetch Star War API.
Here is my code:
import { MOVIES_ERROR, MOVIE_CHARACTERS } from "./types";
// Get all characters
export const getCharacters = (userId) => async (dispatch) => {
try {
const res = await fetch(`https://swapi.dev/api/films/${userId}`);
if (!res.ok) {
throw new Error("sometheing went wrong");
}
const getData = await res.json();
const characters = await getData.characters;
let people = [];
Promise.all(
characters.map((url) =>
fetch(url)
.then((response) => response.json())
.then((name) => people.push(name))
)
);
dispatch({
type: MOVIE_CHARACTERS,
payload: people,
});
} catch (err) {
dispatch({
type: MOVIES_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};
when I make a console log inside a promise. all I got people array filled with all the data, but when I dispatch it I got an empty array in the reducer. can anyone tell me what the mistake that i did?
I got the problem just now, I need to add await before Promise.all :)

React Redux Call action within action and get return value

I am trying to call and action from an action to get a database record by name, then I want to use the ID of the role record in the SignUp action that is currently being called .
How can I reuse the code for my GetRolebyName action from within the sign up action, I was trying to avoid doing the same APi request in two places.
Essentially I am just trying to look up the RoleId when creating a user.
Role actions:
export const fetchRoleByName = name => async dispatch => {
const response = await db.get(`/roles?name=${name}`);
dispatch({
type: FETCH_ROLE,
payload: response.data[0]
});
};
Sign up Action:
export const signUp = values => async (dispatch, getState) => {
const role = await dispatch(fetchRoleByName(values.userType))
const response = await db.post('/users/',
{
...values,
roleId: role.id
}
);
dispatch({
type: SIGN_UP,
payload: response.data
});
history.push('/');
};
Solution:
As pointed out by Kaca992, the fetchRoleByName action never actually returned anything so the change required was as per below;
export const fetchRoleByName = name => async dispatch => {
const response = await db.get(`/roles?name=${name}`);
const data = response && response.data && response.data[0];
dispatch({
type: FETCH_ROLE,
payload: data
});
return data;
};
Inside fetchRoleByName just return response. Return from dispatch is the return value of the inner function:
export const fetchRoleByName = name => async dispatch => {
const response = await db.get(`/roles?name=${name}`);
dispatch({
type: FETCH_ROLE,
payload: response.data[0]
});
return response; (or return response.data[0] if that is the role object you want, but then I would recommend writing it like this: response && response.data && response.data[0] just in case of hitting an unexisting value from db)
};
Hope this helps.

Resources