Put request with Axios | React, Redux - reactjs

I want to make a put request with Axios and I got this inside of my action so far:
export function updateSettings(item) {
return dispatch => {
console.log(item)
return axios.put(`/locks`).then(response => {
console.log(response)
})
}
}
When I console.log item I can see all of things I've typed in my input boxes inside of that object, but later I get 404. I know that I have that URI. Does anyone know how to troubleshoot this problem?

a put response will need an object to send with. the correct axios for put is this:
export function updateSettings(item) {
return dispatch => {
console.log(item)
return axios.put(`/locks`, item).then(response => {
console.log(response)
})
}
}
this is most likely why you get the error because the object to PUT with is undefined.
You can watch this list on the link below, to how to make the correct requests with axios. Axios request methods

A PUT request requires an identifier(e.g id) for the resource and the payload to update with. You seem not to be identifying the resource you want to update, hence 404.
you'd need an id and item like this.
export function updateSettings(id, item) {
return dispatch => {
console.log(item)
return axios.put(`/locks/${id}`, item).then(response => {
console.log(response)
})
}
}

Related

Axios API call returns a 404 on page render, but still returns api objects in terminal

I am using axios to make an api call to an api found on Apihub for a next JS app.
here is the code for the function to make the call to provide a list of property JSON objects.
export const baseUrl = "https://zillow56.p.rapidapi.com"
export const fetchApiListsingsCustom = async (url) => {
const { data } = await axios.get((url), {
method: 'GET',
headers: {
'X-RapidAPI-Key': '328713ab01msh862a3ad609011efp17e6b4jsn0e7112d5ee9a',
'X-RapidAPI-Host': 'zillow56.p.rapidapi.com'
}
});
data.then((res) => {
console.log(res);
})
.catch((error) => {
console.error(error);
});
return data.json();
}
When rendering the page I'm attempting to inject the response's data to dynamically create a list of apartment listings.
I'm trying to use getServerSideProps so that the data is already available by the time a user requests the page. After fetching the data, I want to also print them in the terminal to validate it's success.
export default function Home({ propertiesCustomdata })
export async function getServerSideProps() {
const propertiesCustom = await fetchApiListsingsCustom(`${baseUrl}`)
const propertiesCustomdata = propertiesCustom.json()
return {
props: {
propertiesCustomdata
}
}
}
The problem is, I seem to be getting a 404 error from the axios call, before the page gets a chance to load. When I access this I get a 404 error but I also manage to receive some contents of the call the API was to make.
My apologies if this is unclear, but this is all I know to report on this so far.
Studying async and await, fetch, and axios. Very confusing.

Code not working after redux function in axios call

I'm having trouble with redux/axios. I want to change the store after an axios request is successful, and after the store change, I want to change the application state. I expected the code to get to my function but that does not happen, and I'm not sure why! Is redux async? if so how can I make a sync call? (Left some code bellow)
axios.post(url,{
"system":system,
})
.then(res => {
this.props.setTest(res) #code does not follow this line, no state is set
this.setState({
test_data:res,
redirect:true
})
})
.catch((error)=>{
if(error.response){
if(error.response.data["Error"]){
console.log("There was an error fetching the test")
}
}
})
export function setTest(test){
return {type: "SET_TEST",payload: test}
}
case "SET_TEST":{
console.log("SET_TEST")
return {
...state,
(and other changed args)
};
}
Thanks for the help!
It is very likely that this.props.setTest(res) triggers some kind of error.
Since later you have a catch block where you only handle very specific error, that error makes it never out and you will never know what the error was in the first place until you console.log it.
So:
.catch((error)=>{
if(error.response && error.response.data["Error"]){
console.log("There was an error fetching the test")
} else {
// don't swallow your error, log it!
console.log("some unexpected error happened:", error);
}
I don't think you understood how Redux works. In your case, setTest returns an action. An action needs to be dispatched.
Try this:
import { useDispatch } from "react-redux";
// inside your component
const dispatch = useDispatch();
dispatch(setTest(res));

Display loading state and change route when API call is successfull

While working on a side project, I faced an issue with react-router-dom.
What I want to implement is: When I submit a Form, I need to save the data on my server. While the request is pending, I need to display a loading indicator. Once the server says everything is ok, I need to redirect the user on a new page
action.js
export const addNotification = value => async dispatch => {
dispatch(addNotificationPending())
try {
const response = await client.createNotification(values)
dispatch(addNotificationSuccess(response))
} catch(e) {
dispatch(addNotificationFailure())
}
}
component.js
class CreateNotificationForm extends Component {
onSubmit = (values) => {
this.props.addNotification(parameters, history)
}
render() {
const { isCreating } = this.props
const submitBtnText = isCreating ? 'Creating...' : 'Submit'
return (
<Form>
// content omitted
<Submit value={submitBtnText} />
</Form>
)
}
}
const mapStateToProps = (state) => ({
isCreating: getIsFetching(state)
})
const mapDispatchToProps = (dispatch) => ({ // omitted })
connect(mapStateToProps, mapDispatchToProps)(CreateNotificationForm)
So far so good: When I submit my form, the form's submit button shows a Creating... text.
However, how do I tell react-router to load a new path once the request is successful?
Right now, I've done that by using withRouter and using this.props.history as a second argument for this.props.addNotification.
It works great, but it seems really wrong
I've seen solutions using react-router-redux, but I don't really want to add a new middleware to my store.
Should I make the API call inside my component and use a Promise?
Any help?
Update:
After working a little on my own React project, and thinking about similar situations where I handle route changes there, I decided I want to change my original answer. I think the callback solution is OK, but the solution that you already mentioned of making the API call inside your component and using a promise is better. I realized that I've actually been doing this in my own app for a while now.
I use redux-form in my app, and it provides onSubmitSuccess/onSubmitFail functions that you can use to handle the submit result, and each of those rely on you returning a promise (usually from your action creator).
I think the fact that one of the most popular packages for form submission in React/Redux supports this pattern is an indication that it's probably a good pattern to use. Also, since react-router passes history into your component, it seems logical that they expect most people to do a lot of their programmatic route changes inside the component.
Here's an example of what the promise solution would look like with your code:
action.js
export const addNotification = value => dispatch => {
return new Promise(async (resolve, reject) => {
dispatch(addNotificationPending())
try {
const response = await client.createNotification(values)
dispatch(addNotificationSuccess(response))
resolve(response)
} catch(e) {
dispatch(addNotificationFailure())
reject(e)
}
})
}
component.js
onSubmit = async () => {
try {
await this.props.addNotification(parameters)
this.props.history.push('/new/route')
} catch(e) {
// could use a try/catch block here to display
// an error to the user here if addNotification fails,
// or go to a different route
}
}
Old Answer:
A simple solution would be to allow addNotification() to accept a callback function as an optional second argument.
export const addNotification = (value, callback=null) => async dispatch => {
dispatch(addNotificationPending())
try {
const response = await client.createNotification(values)
dispatch(addNotificationSuccess(response))
(typeof callback === 'function') && callback()
} catch(e) {
dispatch(addNotificationFailure())
}
}
Then inside your component use the router to go to the new route.
onSubmit = (values) => {
this.props.addNotification(parameters, () => {
this.props.history.push('/new/route')
})
}
You should not write your asynchronous calls in reducers or actions as the documentation clearly suggests them to be pure functions. You will have to introduce a redux-middleware like redux-thunk or redux-saga (I personally prefer sagas)
All your async calls will happen inside the middleware, and when it succeeds, you can use react-routers history .replace() or .push() methods to update your route. Let me know if it makes sense
You can use one popular package axios
See Here https://www.npmjs.com/package/axios
and you can implement your login like
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
You can write your loader login while calling api
and then you can hide your loader in .then

Better ways to handle REST API call in Redux

In my app, I need to call several REST API endpoints:
// The UI Class
class LoginForm extends Component {
handleSubmit(){
store.dispatch(login(username, password));
}
}
// An action
function login(username, password){
return dispatch => {
fetch(LOGIN_API, {...})
.then(response => {
if (response.status >= 200 && response.status < 300){
// success
} else {
// fail
}
})
}
}
The gist is above and easy to understand. User triggers an action, an ajax call to the corresponding endpoint is made.
As I am adding more and more API endpoints, I end up with a bunch of functions similar to the skeleton of the login function above.
How should I structure my code in such a way that I don't repeat myself with duplicate ajax functions?
Thanks!
I strongly suggest you to read this popular github sample project. At first it is hard to understand but don't worry and continue to read and realize what is happening in that.
It uses very clear and simple way to handle all of your API calls. when you want to call an API, you should dispatch an action with specific structure like this:
{
types: [LOADING, SUCCESS, FAIL],
promise: (client) => client.post('/login', {
data: {
name: name
}
})
}
and it will handle these kind of actiona by a custom middleware.
The way I handle a similar situation is to have 2 wrapper for API calls:
function get(url) {
return fetch(url)
.then(response => {
if(response.status >= 200 && response.status < 300) {
return response
}
else {
let error = new Error(response.statusText)
error.response = response
throw error
}
})
.then(response=> response.json())
}
This wrapper will take a url and return the json data. Any error that happens (network, response error or parsing error) will be caught by the .catch of get
A call basically looks like that:
get(url)
.then(data => dispatch(someAction(data)))
.catch(error => dispatch(someErrorHandler(error)))
I also have a post wrapper that in addition sets the header for CSRF and cleans the data. I do not post it here as it is quite application-related but it should be quite ovious how to do it.

Data fetching with React Native + Redux not working

I am building my first React Native app and use Redux for the data flow inside my app.
I want to load some data from my Parse backend and display it on a ListView. My only issues at the moment is that for some reason, the request that I create using fetch() for some reason isn't actually fired. I went through the documentation and examples in the Redux docs and also read this really nice blog post. They essentially do what I am trying to achieve, but I don't know where my implementation differs from their code samples.
Here is what I have setup at the moment (shortened to show only relevant parts):
OverviewRootComponent.js
class OverviewRootComponent extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch( fetchOrganizations() )
}
}
Actions.js
export const fetchOrganizations = () => {
console.log('Actions - fetchOrganizations');
return (dispatch) => {
console.log('Actions - return promise');
return
fetch('https://api.parse.com/1/classes/Organization', {
method: 'GET',
headers: {
'X-Parse-Application-Id': 'xxx',
'X-Parse-REST-API-Key': 'xxx',
}
})
.then( (response) => {
console.log('fetchOrganizations - did receive response: ', response)
response.text()
})
.then( (responseText) => {
console.log('fetchOrganizations - received response, now dispatch: ', responseText);
dispatch( receiveOrganizations(responseText) )
})
.catch( (error) => {
console.warn(error)
})
}
}
When I am calling dispatch( fetchOrganizations() ) like this, I do see the logs until Actions - return promise, but it doesn't seem to actually to fire off the request. I'm not really sure how how I can further debug this or what resources to consult that help me solve this issue.
I'm assuming that Redux is expecting a Promise rather than a function.. Is that true?
If so, I think your return function may not be working.
You have a new line after your return, and it's possible JavaScript is (helpfully) inserting a semicolon there.
See here: Why doesn't a Javascript return statement work when the return value is on a new line?

Resources