How to use useSWRMutation with a dynamic URL? - swr

Let's say I have a component that needs to send a request when a button is clicked
function Component() {
function handleClick () {
// Send request
}
return (
<button onClick={handleClick}>Click me</button>
)
}
I want to use useSWRMutation to send a POST request to the server (e.g. POST /api/clicks/:clickId)
async function sendClick (url, { arg }) {
await fetch(url, { // Question 1: Should it be like `${url}/${arg.clickId}`?
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(arg)
});
}
function Component() {
const { trigger } = useSWRMutation('/api/clicks/', sendClick); // Question 2: What URL (key) should be here? 1) /api/clicks/:clickId 2) /api/clicks 3) Nothing?
function handleClick () {
trigger({ id: "clickId", otherData: [] });
}
return (
<button onClick={handleClick}>Click me</button>
)
}
What key should we use in useSWRMutation when sending a request with dynamic URL (e.g. /api/clicks/:clickId)?
P.S. I have feeling that I don't need to use useSWRMutation hook here as soon as I don't need to cache or invalidate the cache after. The only reason why I'm using it is isLoading (or isMutating).

Related

Variable in data section can't get API response value (response.data)

I accessed API to upload image and return the image URL with Vue app. I want to set API response value to imgUrl1 in data section. I' sure getting correct response in console but imgUrl1 is still empty. Anybody idea ?? Thank you so much !
Vue
data () {return
{
imgUrl1:'',→empty
}
},
methods: {
uploadFile1: function () {
var img_file1 = this.$refs.img1.files[0]
var params = new FormData()
params.append('image', img_file1)
params.append('client_name', this.tableSelected)
axios.post("http://127.0.0.1:5000/", params
).then(function (response) {
console.log(response.data)→image url exists
this.imgUrl1 = response.data
}).catch(function (error) {
for(let key of Object.keys(error)) {
console.log(key);
console.log(error[key]);
}
});
}
console.log(response.data)
https://storage.googleapis.com/dashboard_chichat/img/クライアント名/xxxxxxxxnQSkX6Wudy.jpg
try using arrow functions in your then callback so the value of this is your Vue component.
methods: {
uploadFile() {
...
axios.post('', params)
.then((response) => {
this.imgUrl1 = response.data
})
}
}
the equivalent of it without arrow functions is:
methods: {
uploadFile() {
...
const _this = this;
axios.post('', params)
.then(function (response) {
_this.imgUrl1 = response.data
})
}
}

Cancel an axios request, when not having the fetch in useEffect

I am trying to implement the cancel request function for my axios post. I created own js files for the functions and I am importing them into my screens. Here is an example
App.js
cancelToken.current = axios.CancelToken.source()
async function getFeed() {
let x = await service.getUserFeed(user_id, cancelToken);
setData(x); }
getFeed();
return () => {
cancelToken.cancel();
}
},[user_id]);
service.js:
getUserFeed: async (token, user_id, source) => {
let x;
await axios.post(Default.apiEndpoint + 'feed',
{
},
{
cancelToken: source.token,
headers: {
'Accept': "application/json",
'Content-Type': "application/json",
'user_id': user_id,
}
}).then(response => {
x = response.data;
}).catch(error => {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
else {
x = error.response.status;
}
});
return x;
},
If I am calling the request in the hook itself it is working. So I am not even sure, if it is possible, because the request is not triggered, when the user leaves the page. So I would need to cancel the request in the service.js itself (I guess). Did anyone implement that already and can help me here?
Thanks

Vuex state is sometimes empty (undefined), especially when I refresh the page and sometimes it works

Vuex state is sometimes empty (undefined), especially when I refresh the page. And sometimes it works.
action:
getSkills(context) {
let url = "/skills";
const headers = {
"x-api-key": process.env.VUE_APP_SIRH_X_API_KEY,
Authorization: localStorage.getItem("access_token"),
};
return axios({
method: "get",
url: url,
headers: headers,
}).then((response) => {
context.commit("getSkill", response.data.data.skills);
}).catch((e) => {
console.log(e);
});
},
getter:
Skills: (state) => state.Skills,
mutation :
getSkill(state, skills) {
state.Skills = skills;
},
state :
Skills: [],
and the vue :
computed: {
...mapState({}),
...mapGetters(["Candidate", "Skills"])
},
mounted() {
this.getSkills();
this.id = this.$route.params.id;
this.Skills.forEach(element => this.skill_list.push(element.skill_name));
},
methods: {
...mapActions(["attachSkillCandidate", "getSkills"]),
}
Can anyone help me to solve this issue ?
Thanks!
The getSkills action is performing an asynchronous request. You need to wait for the request to finish before you can access this.Skills otherwise the data will not be set yet.
You need async and await (the "modern" solution):
async mounted() {
await this.getSkils();
this.id = this.$route.params.id;
this.Skills.forEach(element => this.skill_list.push(element.skill_name));
}
or:
mounted() {
this.getSkils().then(() => {
this.id = this.$route.params.id;
this.Skills.forEach(element => this.skill_list.push(element.skill_name));
});
}

globalize axios as API wrapper in vue project

I have almost 13 Axios requests in my Vue application. which are almost the same
axios({
method: 'post',
url: `${this.$root.api_url}/v2/cameras/${this.selected.exid}/nvr/snapshots/extract`,
data: {
start_date: moment(this.fromDateTime).format(),
end_date: moment(this.toDateTime).format(),
schedule: this.schedule,
interval: this.interval,
create_mp4: this.create_mp4,
inject_to_cr: this.inject_to_cr,
jpegs_to_dropbox: this.jpegs_to_dropbox,
requester: this.$root.user.email,
api_key: this.selected.api_key,
api_id: this.selected.api_id
}
}).then(response => {
if (response.status == 201) {
this.showSuccessMsg({
title: "Success",
message: "Snapshot Extractor has been added (Local)!"
});
this.$events.fire('se-added', {})
this.clearForm()
} else {
this.showErrorMsg({
title: "Error",
message: "Something went wrong!"
})
}
})
I pass the method, URL and data.. and do a few things in response and in case of error.
How can I reduce that so much code? I have this idea to make an API file for this where, the method will accept, API.get(method, URL, data) and I will have {message, statusCode} in return. and then on the basis of that, I can do other stu7ff.
I tried to follow some documentation online but it didn't work. Is there any suitable way to reduce this code.
Is it even possible to give success and error message as well in API.get or post or delete that it would be very minimal when you send the API request?
EDIT: so i guess you need something like a class here:
class API {
static get(url, callback) {
axios({
method: "get",
url: url,
data: data
}).then(response => {
callback(response);
});
}
static post(url, data, callback) {
axios({
method: "post",
url: url,
data: data
}).then(response => {
callback(response);
});
}
}
API.post("url", data, response => {
console.log(response);
});
API.get("url", response => {
console.log(response);
});
I use yamlful
You make a .yml file which includes
events:
- method: get
get: /events/:id
then API calls become
const response = await this.$api.events.get(2)
Furthermore, I inject methods into my context
// api.js
async function populateEvents (app, id) {
const response = await app.$api.events.get(id)
return response
}
export default ({ app, store }, inject) => {
inject('populateEvents', id => populateEvents(app, id))
}
// any_file.vue
this.populateEvents(12)
and in api.js you can generalize your api calls, so if any 2 api calls do the same stuff, you can refactor that repeated code into a separate method

What is the correct way to use AsyncStorage to update state in React-Native?

I'm trying to make a GET request to a server to retrieve a list of products in JSON form. I then want to put the data into AsyncStorage so I can display the products in the view. What's the correct way to do this?
What I've researched:
on https://facebook.github.io/react-native/docs/asyncstorage.html , in the example, they explain how to retrieve a value from AsyncStorage, not set it and retrieve it at the same time
What I have:
componentDidMount () {
this.fetchProducts()
this._loadInitialState().done();
}
_loadInitialState = async () => {
try {
var value = await AsyncStorage.getItem('products')
if (value != null) {
this.setState({products: value});
}
} catch (error) {
console.log("error setting product list");
}
}
fetchProducts() {
fetch("http://localhost:3000/products",{
method: "GET",
headers: {
'Content-Type': 'application/json'
},
})
.then((response) => (response.json()))
.then((data) => setProductList(data));
}
setProductList(json_data) {
Async.setItem('products': json_data);
}
render() {
console.log(this.state.products)
//render view
}
-> this.state.products is null and I know for sure the server returns a response through curl. I'm new to react-native so perhaps my thinking is off. Could someone explain the correct way to do this or suggest an alternative method?
What I know
Async storage is a key value store where an app can place its data. This data can be put from async storage into the object's state and the view will update accordingly
Instead of setting and getting from async storage, you can just set it to state once you get the data from your fetch request:
componentDidMount () {
this.fetchProducts()
}
fetchProducts() {
fetch("http://localhost:3000/products",{
method: "GET",
headers: {
'Content-Type': 'application/json'
},
})
.then((response) => (response.json()))
.then((data) => setProductList(data));
}
setProductList(json_data) {
this.setState({ products: json_data }, () => { //Here
Async.setItem('products': json_data);
}
}
render() {
console.log(this.state.products)
//render view
}