My userData return undefined react js fetch - reactjs

On my console log, i can see my object for my response.json but i think i forget something for my setUser because my object return undefined ?
function Profil() {
const [user, setUser] = useState({});
const getUser = () => {
const headers = new Headers({
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
Authorization: "Bearer " + localStorage.getItem("token"),
});
const options = {
method: "GET",
headers: headers,
};
fetch(
"https://..../user",
options
)
.then((response) => {
return console.log(response.json());
})
.then(
(responseObject) => {
const userData = responseObject;
setUser({ ...user, userData });
console.log(user);
},
(error) => {
console.log(error);
}
);
};
useEffect(() => {
getUser();
}, []);
return (
<div>
<h1> Prénom</h1>
</div>
);
}
export default Profil;
my object on my console log is
[[PromiseResult]]: Object
email: "test#gmail.com"
firstname: "test"
lastname: "test"
_id: "61519405b8dc4a001be666"

You're returning undefined from your Promise:
.then((response) => {
return console.log(response.json());
})
response.json() itself returns a Promise, so return that:
.then((response) => {
return response.json();
})
There's no need to log the Promise itself. If you want to log the raw response JSON to the console then do that in the next Promise:
.then(
(responseObject) => {
// here:
console.log(responseObject);
const userData = responseObject;
setUser({ ...user, userData });
console.log(user);
},
(error) => {
console.log(error);
}
);
Additionally, be aware of what this is doing:
console.log(user);
This will log the state of user when this code is running. It will not reflect the update from here:
setUser({ ...user, userData });
Because that state update happens asynchronously. If you want to log the updated state value, either do it in a useEffect, or directly in the rendering of the component, or just log the object you're passing to setUser.
You also don't need your userData variable at all. It adds no value and is just a reference to responseObject.

Related

useSWR not getting data from api while fetch() to the same adress returns data

I really don't understand why I can't get useSWR to work in my app.
I have been trying for two days and can't seems to find the reason.
The normal fetch works fine calling the same address in the same function.
const address =server+ `/api/google/getData?term=` + endRow.name;
const fetcher = async (url) => await axios.get(url).then((res) => res.data);
const { data, error } = useSWR(address, fetcher);
//Always undefined
console.log(data)
//Gets the data
async function test() {
const res = await fetch(address)
console.log(await res.json())
}
test();
API method:
import { connectToDatabase } from '../../../util/mongodbUtil'
export default async (req, res) => {
const { db } = await connectToDatabase();
return new Promise(async (resolve, reject) => {
try{
res.status(201).json({ response: ["TESTDATA"], success: true })
resolve()
} catch (e) {
console.log(e)
res.status(400).json({ success: false })
resolve()
}
})
}
in _app configure your SWR
<SWRConfig value={{
refreshInterval: 0,
fetcher: (url: string, token: string) => fetch(url, {
headers: token ? {Authorization: token} : undefined
}).then((res) => res.json())
}}>
...
<Component {...pageProps} />
then you can use const {data, error} = useSWR([requestedUrl, token])

React Fetch with State Value

I've two different API URL. I can get current user's ID with /api/current_user and save into "currentuser" state. I want to fetch all currentuser's from MySQL. My API URL works. But i couldn't fetch with currentuser state variable.
This link returns currentuser's ID. It works.
useEffect(()=>{
fetch('http://localhost:8000/api/current_user/', {
headers: {
Authorization: `JWT ${localStorage.getItem('token')}`
}
})
.then(res => res.json())
.then(json => {
setCurrentuser(json.id);
});
},[])
Then i want to use that ID with currentuser state.
Axios.request({
method: 'POST',
url: 'http://localhost:3001/api/post',
data: {
curus: `${currentuser}` // I'm trying to use currentuser state on here.
},
})
.then(response => {
return response.data;
})
.then(data => {
let tmpArray2 = []
const tmpArray = []
bla bla bla ...
Finally request payload returns curus: ""
So it have a null value. I can use this state value inside return function.
Also that's my node server's index.js:
app.post('/api/post', (req, res) => {
const currentt = req.body.curus
const sqlSelect = "SELECT * FROM messagestable WHERE sender='" + currentt + "' OR recipient ='" + currentt + "' ";
db.query(sqlSelect, (err, result) => {
res.send(result);
console.log(currentt)
});
})
I want to fetch all messages from MySQL but just for currentuser. Not all users messages. May you help me? Thanks a lot!
You can't call fetch and Axios.request in succession because setCurrentuser is async and when you use currentuser in Axios.request you don't know if currentuser has the very last value.
Much better split fetch and Axios.request into 2 useEffect in this way:
useEffect(()=>{ //<-- this will be fired on component's loading
fetch('http://localhost:8000/api/current_user/', {
headers: {
Authorization: `JWT ${localStorage.getItem('token')}`
}
})
.then(res => res.json())
.then(json => {
setCurrentuser(json.id);
});
},[])
useEffect(() => { //<-- this one will be fired every time you change currentuser and will contains the very last value of currentuser
Axios.request({
method: 'POST',
url: 'http://localhost:3001/api/post',
data: {
curus: `${currentuser}`
},
})
.then(response => {
return response.data;
})
.then(data => {
let tmpArray2 = []
const tmpArray = []
bla bla bla ...
}, [currentuser])

How to set fetch data to text field in react-native function component

I am learning react-native and have a question about fetching data and passing them to a text component.
I fetched my data from my node.js back-end but don't know how to pass this data to component. Below is the code that i have tried so far.
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
console.log('Test');
console.log(response);
const array = response;
for (const i of array) {
const total = i.total;
setDetails(total);
console.log(total);
}
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (
<Text Value={details}></Text> //I need to set my fetch data this text component
)
}
if you have an array of values and you want to show them you can use:
const TableView = () => {
const [details, setDetails] = useState('');
const getUserData = async () => {
fetch('https://----.herokuapp.com/getIncomePerUser', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: data,
month: value,
}),
})
.then(response => response.json())
.then(response => {
setDetails(response.map(r => r.total));
})
.catch(err => {
console.log(err);
});
});
};
useEffect(() => {
getUserData();
}, []);
return (<>
{details.map((d, i) => <Text key={i}>{d}</Text>)}
</>)
}
if you have a single value just replace your text component with:
<Text>{details}</Text>

called async function from state is not waiting (react)

I call a state function in my component, the function should change the state(and it does but late), i want to log the change but the log triggers before the state is changed
this is the function in the state:
const login = async (user, password) => {
const body = {
username: user,
password: password,
};
await axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
and this is the call in the component
const onSubmit = (e) => {
e.preventDefault();
login(user, password);
console.log(credes);
};
"credes" is the state for that response, but it keeps printing the initial state witch is an empty object
the function triggers on the form submission but logs first and updates the state later.
As pointed out by bubulledu93, ronakvp and coreyward, I was butchering the syntax. I was trying to perform two actions in one function, so I moved the log into a useEffect to watch for changes in the "credes" hope is the right way but is working as I needed it.
const login = (user, password) => {
const body = {
username: user,
password: password,
};
axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
and the call in the component + the useEffect
const onSubmit = (e) => {
e.preventDefault();
login(user, password);
};
useEffect(() => {
if (credes.success) {
console.log(credes.data);
}
}, [credes]);
There isn't any benefit to awaiting as the last call in a function. Instead of using async and await, simply return the Promise chain started by axios.post() to onSubmit and then chain on it (or use await there):
const login = (user, password) => {
const body = {
username: user,
password: password,
};
return axios
.post('/sessions', body, {
headers: { 'Content-Type': 'application/json' },
})
.then((resp) => {
dispatch({ type: LOGIN, payload: resp.data.data });
})
.catch((err) => {
console.log(err.response.data);
});
};
// Option 1:
const onSubmit = (e) => {
e.preventDefault();
login(user, password)
.then(() => {
console.log(credes);
});
};
// Option 2:
const onSubmit = async (e) => {
e.preventDefault();
await login(user, password);
console.log(credes)
}

problem with fetch in componentDidMount()

my list of users is undefined when i try to console.log it.
Maybe i didn't get something ?
I'd like to get my list of users from my api who works (tested with postman) and put it into the console next i'd like to map my users to show it on the app
class Test extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
}
}
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => {
return res.json();
})
.then(users =>
this.setState({users}, () =>
console.log("list of users => " + users)));
}
render() {
return (
<div className="form">
<ul>
{this.state.users.map((user) =>
<li key="user._id">{ user.name }</li>
)}
</ul>
</div>
);
}
} export default Test;
Thanks for help !
You are calling res.json() rather than returning res.json() from the first then on your fetch call
I've found this pattern to be helpful:
fetch(url)
.then(res => res.ok ? res.json() : Promise.reject())
As your code is now, users (the parameter in the second then would be undefined, because you are not returning anything from the first then
you have to return the res.json() to use it in the next .then()
.then(res => {
res.json();
})
should be
.then(res =>
res.json();
)
Or
.then(res => {
return res.json();
})
https://javascript.info/promise-chaining
You should be passing your res into res.json() and returning the results into your state.
componentDidMount() {
console.log("component did mount");
fetch("/user/list")
.then(res => res.json())
.then(users =>
this.setState(users,
() => {
console.log("list of users => " + users)
})
);
}
Michael Jasper response help me so much!
I found that fetch with GET method does not work if we pass any request body.
the full example is here
https://github.com/alexunjm/todo-list-react
const buildRequestOptions = ({
method = "GET",
raw = null, // I had my error here!, with GET raw need to be null
customHeaders = {name: 'value'},
}) => {
var myHeaders = buildHeaders(customHeaders);
var requestOptions = {
method,
headers: myHeaders,
body: raw,
redirect: "follow",
};
return requestOptions;
};
const listTasks = () => {
const url = `${uriBase}/task/sample`;
const requestOptions = buildRequestOptions({
customHeaders: { "Content-Type": "application/json" },
});
return fetch(url, requestOptions);
}
const asyncFn = ({
promiseToWait,
pendingFn,
successFn,
errorFn,
}) => {
return (dispatch) => {
dispatch(pendingFn());
promiseToWait
.then((res) => {
if (res.ok) {
return res.json();
}
// handled from server status 422 and 401
if (res.status === 422) {
// error message on body from server
return res.json();
}
if (res.status === 401) {
// custom error message hardcoded
return {errors: {action: 'no authorized'}}
}
console.log("http response no controlled", res);
return Promise.reject();
})
.then((body) => {
if (body.errors) {
const errors = Object.keys(body.errors).map(
(key) => key + " " + body.errors[key]
);
dispatch(errorFn(errors.join("; ")));
} else {
dispatch(successFn(body));
}
return body;
})
.catch((error) => {
console.log("error", error);
dispatch(errorFn("Unavailable server connection"));
});
};
};
const queryTasks = () => {
return asyncFn({
promiseToWait: listTasks(),
pendingFn: apiPending,
successFn: apiSuccessList,
errorFn: apiError,
});
}

Resources