React Native
...
Cloud Functions
Triggers
15 min
using cloud functions in a react native app introduction in this guide, you will learn how to use the parse cloud code functions from a react native app you will see examples of triggers implemented using cloud functinos, and also check how to implement a react native component using these functions and back4app prerequisites to complete this tutorial, you will need a react native app created and connected to back4app understand how to deploy a cloud function on back4app if you want to run this guide’s example application, you should set up the react native paper react native paper library goal run parse cloud code on back4app from a react native app 1 understanding cloud code functions in your applications, there will be times that you will need to perform certain data operations or heavy processing that shouldn’t be done on mobile devices for these cases, you may use cloud code functions, that run directly on your parse server and are called using parse api note that this also enables changing some part of your app’s logic without needing to release a new version on the app stores, which can be useful in some cases there are two main types of cloud code functions, generic functions, using define define and holding any type of code you want, and triggers, that are fired when certain events occur in your parse server automatically in the next step, you will be presented with examples for most of these function types, which can be created and deployed directly in your back4app dashboard or via cli you can check how to perform this in our cloud functions starter guide https //www back4app com/docs/get started/cloud functions 2 cloud code reference cloud functions cloud functions 1 // this a generic cloud function that may contain any type of operation, 2 // these should be called via api in your app to be run 3 parse cloud define("getaveragemoviereviews", async (request) => { 4 const query = new parse query("review"); 5 // parameters can be passed in your request body and are accessed inside request params 6 query equalto("movie", request params movie); 7 const results = await query find(); 8 let sum = 0; 9 for (let review of results) { 10 sum += review\ get("stars"); 11 } 12 return { 13 result sum / results length, 14 } 15 }); response save triggers beforesave 1 // this will run every time an object of this class will be saved on the server 2 parse cloud beforesave("product", (request) => { 3 // you can change any data before saving, can be useful for trimming text 4 // or validating unique fields 5 const name = request object get("description"); 6 if (description length > 140) { 7 // truncate and add a 8 request object set("description", comment substring(0, 137) + " "); 9 } 10 }); aftersave 1 // this will always run after saving an object of this class 2 parse cloud aftersave("comment", async (request) => { 3 // you can use this method for changing other classes, like handling 4 // a comment counter for a post 5 const query = new parse query("post"); 6 try { 7 let post = await query get(request object get("post") id); 8 post increment("comments"); 9 return post save(); 10 } catch (error) { 11 console error("got an error " + error code + " " + error message); 12 } 13 }); delete triggers beforedelete 1 // this will be called before deleting an object, useful for checking 2 // for existing dependent conditions 3 parse cloud beforedelete("album", async (request) => { 4 // this won't proceed deleting if the condition is not met, protection your 5 // data 6 const query = new parse query("photo"); 7 query equalto("album", request object); 8 const count = await query count(); 9 if (count > 0) { 10 throw "can't delete album if it still has photos "; 11 } 12 }); afterdelete 1 // called after deleting an object, useful for cascade deleting related 2 // objects 3 parse cloud afterdelete("post", async (request) => { 4 // delete all post comments after deleting the post 5 const query = new parse query("comment"); 6 query equalto("post", request object); 7 try { 8 let results = await query find(); 9 await parse object destroyall(results); 10 } catch (error) { 11 console error("error finding related comments " + error code + " " + error message); 12 } 13 }); file triggers beforesavefile 1 // can be called to change any file properties, like renaming it 2 parse cloud beforesavefile(async (request) => { 3 const { file } = request; 4 const filedata = await file getdata(); 5 // note that the new file will be saved instead of the user submitted one 6 const newfile = new parse file('a new file name txt', { base64 filedata }); 7 return newfile; 8 }); aftersavefile 1 // can be called for managing file metadata and creating 2 // your file referencing object 3 parse cloud aftersavefile(async (request) => { 4 const { file, filesize, user } = request; 5 const fileobject = new parse object('fileobject'); 6 fileobject set('file', file); 7 fileobject set('filesize', filesize); 8 fileobject set('createdby', user); 9 const token = { sessiontoken user getsessiontoken() }; 10 await fileobject save(null, token); 11 }); beforedeletefile 1 // useful for checking conditions in objects using the file to be deleted 2 parse cloud beforedeletefile(async (request) => { 3 // only deletes file if the object storing it was also deleted before 4 const { file, user } = request; 5 const query = new parse query('fileobject'); 6 query equalto('filename', file name()); 7 const fileobjectcount = await query count({ usemasterkey true }); 8 if (fileobjectcount > 0) { 9 throw 'the fileobject should be delete first!'; 10 } 11 }); afterdeletefile 1 // useful for cleaning up objects related to the file 2 parse cloud afterdeletefile(async (request) => { 3 // note that this example is the opposite of the beforedeletefile one, 4 // this one will clean up fileobjects after deleting the file 5 const { file } = request; 6 const query = new parse query('fileobject'); 7 query equalto('filename', file name()); 8 const fileobject = await query first({ usemasterkey true }); 9 await fileobject destroy({ usemasterkey true }); 10 }); find triggers beforefind 1 // this will be called before any queries using this class 2 parse cloud beforefind('myobject', (request) => { 3 // useful for hard setting result limits or forcing 4 // certain conditions 5 let query = request query; 6 query limit(5); 7 }); afterfind 1 // this will be called after the query is done in the database 2 parse cloud afterfind('myobject', (req) => { 3 // can be used in rare cases, like force reversing result ordering 4 let results = req objects; 5 results = results reverse(); 6 return req objects; 7 }); session triggers beforelogin 1 // can be used for checking for user permissions and state 2 parse cloud beforelogin(async (request) => { 3 // doesn't allow banned users to login 4 const { object user } = request; 5 if (user get('isbanned') === true) { 6 throw 'access denied, you have been banned '; 7 } 8 }); afterlogout 1 // can be used for cleaning up user actions after logging out 2 parse cloud afterlogout(async (request) => { 3 // sets custom online flag to false 4 const { object session } = request; 5 const user = session get('user'); 6 user set('isonline', false); 7 await user save(null, { usemasterkey true } ); 8 }); 3 using cloud code from a react native component let’s now create an example parse cloud code function and call it inside a component in react native, with a simple interface having a label showing the function result and also a form for adding new objects our cloud function will calculate the average of the ratings of every movie review review object in our app, which is a parse object parse object class composed of text text , rate rate and movie movie fields here is the function code 1 parse cloud define("getmovieaveragerating", async (request) => { 2 const query = new parse query("review"); 3 query equalto("movie", request params movie); 4 const results = await query find(); 5 let sum = 0; 6 for (let review of results) { 7 sum += review\ get("rate"); 8 } 9 return { 10 result sum / results length, 11 }; 12 }); to call this cloud function in react native, you need to use the parse cloud run parse cloud run method, passing as an argument the function name and also any necessary parameters inside an object javascript 1 const rungetmovieaveragerating = async function () { 2 try { 3 const params = { 4 movie 'mission very possible', 5 }; 6 let resultobject = await parse cloud run( 7 'getmovieaveragerating', 8 params, 9 ); 10 // set query results to state variable using state hook 11 setratingsaverage(resultobject result tofixed(1)); 12 return true; 13 } catch (error) { 14 // error can be caused by lack of internet connection 15 // or by not having an valid review object yet 16 alert alert('error!', error message); 17 return false; 18 } 19 };1 const rungetmovieaveragerating = async function () promise\<boolean> { 2 try { 3 const params {movie string} = { 4 movie 'mission very possible', 5 }; 6 let resultobject {result number} = await parse cloud run( 7 'getmovieaveragerating', 8 params, 9 ); 10 // set query results to state variable using state hook 11 setratingsaverage(resultobject result tofixed(1)); 12 return true; 13 } catch (error) { 14 // error can be caused by lack of internet connection 15 // or by not having an valid review object yet 16 alert alert('error!', error message); 17 return false; 18 } 19 }; we can also enforce that the reviews’ texts are kept short by using a beforesave beforesave trigger function for the review review object here is the function code javascript 1 parse cloud beforesave("review", (request) => { 2 const text = request object get("text"); 3 if (text length > 20) { 4 // truncate and add a 5 request object set("text", text substring(0, 17) + " "); 6 } 7 }); this is how the full component code is laid out javascript 1 import react, {usestate} from 'react'; 2 import { 3 alert, 4 image, 5 view, 6 platform, 7 scrollview, 8 stylesheet, 9 } from 'react native'; 10 import parse from 'parse/react native'; 11 import { 12 list, 13 title, 14 textinput as papertextinput, 15 button as paperbutton, 16 text as papertext, 17 } from 'react native paper'; 18	 19 export const movieratings = () => { 20 // state variable 21 const \[queryresults, setqueryresults] = usestate(null); 22 const \[ratingsaverage, setratingsaverage] = usestate(''); 23 const \[reviewtext, setreviewtext] = usestate(''); 24 const \[reviewrate, setreviewrate] = usestate(''); 25	 26 const rungetmovieaveragerating = async function () { 27 try { 28 const params = { 29 movie 'mission very possible', 30 }; 31 let resultobject = await parse cloud run( 32 'getmovieaveragerating', 33 params, 34 ); 35 // set query results to state variable using state hook 36 setratingsaverage(resultobject result tofixed(1)); 37 return true; 38 } catch (error) { 39 // error can be caused by lack of internet connection 40 // or by not having an valid review object yet 41 alert alert( 42 'error!', 43 'make sure that the cloud function is deployed and that the review class table is created', 44 ); 45 return false; 46 } 47 }; 48	 49 const doreviewquery = async function () { 50 // create our query 51 let parsequery = new parse query('review'); 52 try { 53 let results = await parsequery find(); 54 // set query results to state variable 55 setqueryresults(results); 56 return true; 57 } catch (error) { 58 // error can be caused by lack of internet connection 59 alert alert('error!', error message); 60 return false; 61 } 62 }; 63	 64 const createreview = async function () { 65 try { 66 // this values come from state variables linked to 67 // the screen form fields 68 const reviewtextvalue = reviewtext; 69 const reviewratevalue = number(reviewrate); 70	 71 // creates a new parse object instance 72 let review = new parse object('review'); 73	 74 // set data to parse object 75 // simple title field 76 review\ set('text', reviewtextvalue); 77	 78 // simple number field 79 review\ set('rate', reviewratevalue); 80	 81 // set default movie 82 review\ set('movie', 'mission very possible'); 83	 84 // after setting the values, save it on the server 85 try { 86 await review\ save(); 87 // success 88 alert alert('success!'); 89 // updates query result list 90 doreviewquery(); 91 rungetmovieaveragerating(); 92 return true; 93 } catch (error) { 94 // error can be caused by lack of internet connection 95 alert alert('error!', error message); 96 return false; 97 } 98 } catch (error) { 99 // error can be caused by lack of field values 100 alert alert('error!', error message); 101 return false; 102 } 103 }; 104	 105 return ( 106 <> 107 \<view style={styles header}> 108 \<image 109 style={styles header logo} 110 source={ { 111 uri 112 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png', 113 } } 114 /> 115 \<papertext style={styles header text}> 116 \<papertext style={styles header text bold}> 117 {'react native on back4app '} 118 \</papertext> 119 {' cloud code movie ratings'} 120 \</papertext> 121 \</view> 122 \<scrollview style={styles wrapper}> 123 \<view> 124 \<title>{'mission very possible reviews'}\</title> 125 \<papertext>{`ratings average ${ratingsaverage}`}\</papertext> 126 {/ query list /} 127 {queryresults !== null && 128 queryresults !== undefined && 129 queryresults map((result) => ( 130 \<list item 131 key={result id} 132 title={`review text ${result get('text')}`} 133 description={`rate ${result get('rate')}`} 134 titlestyle={styles list text} 135 style={styles list item} 136 /> 137 ))} 138 {queryresults === null || 139 queryresults === undefined || 140 (queryresults !== null && 141 queryresults !== undefined && 142 queryresults length <= 0) ? ( 143 \<papertext>{'no results here!'}\</papertext> 144 ) null} 145 \</view> 146 \<view> 147 \<title>action buttons\</title> 148 \<paperbutton 149 onpress={() => rungetmovieaveragerating()} 150 mode="contained" 151 icon="search web" 152 color={'#208aec'} 153 style={styles list button}> 154 {'calculate review average'} 155 \</paperbutton> 156 \<paperbutton 157 onpress={() => doreviewquery()} 158 mode="contained" 159 icon="search web" 160 color={'#208aec'} 161 style={styles list button}> 162 {'query reviews'} 163 \</paperbutton> 164 \</view> 165 \<view> 166 \<title>add new review\</title> 167 \<papertextinput 168 value={reviewtext} 169 onchangetext={text => setreviewtext(text)} 170 label="text" 171 mode="outlined" 172 style={styles form input} 173 /> 174 \<papertextinput 175 value={reviewrate} 176 onchangetext={text => setreviewrate(text)} 177 keyboardtype={'number pad'} 178 label="rate (1 5)" 179 mode="outlined" 180 style={styles form input} 181 /> 182 \<paperbutton 183 onpress={() => createreview()} 184 mode="contained" 185 icon="plus" 186 style={styles submit button}> 187 {'add'} 188 \</paperbutton> 189 \</view> 190 \</scrollview> 191 \</> 192 ); 193 }; 194	 195 // these define the screen component styles 196 const styles = stylesheet create({ 197 header { 198 alignitems 'center', 199 paddingtop 30, 200 paddingbottom 50, 201 backgroundcolor '#208aec', 202 }, 203 header logo { 204 height 50, 205 width 220, 206 resizemode 'contain', 207 }, 208 header text { 209 margintop 15, 210 color '#f0f0f0', 211 fontsize 16, 212 }, 213 header text bold { 214 color '#fff', 215 fontweight 'bold', 216 }, 217 wrapper { 218 width '90%', 219 alignself 'center', 220 }, 221 list button { 222 margintop 6, 223 marginleft 15, 224 height 40, 225 }, 226 list item { 227 borderbottomwidth 1, 228 borderbottomcolor 'rgba(0, 0, 0, 0 12)', 229 }, 230 list text { 231 fontsize 15, 232 }, 233 form input { 234 height 44, 235 marginbottom 16, 236 backgroundcolor '#fff', 237 fontsize 14, 238 }, 239 submit button { 240 width '100%', 241 maxheight 50, 242 alignself 'center', 243 backgroundcolor '#208aec', 244 }, 245 });1 import react, {fc, reactelement, usestate} from 'react'; 2 import { 3 alert, 4 image, 5 view, 6 platform, 7 scrollview, 8 stylesheet, 9 } from 'react native'; 10 import parse from 'parse/react native'; 11 import { 12 list, 13 title, 14 textinput as papertextinput, 15 button as paperbutton, 16 text as papertext, 17 } from 'react native paper'; 18	 19 export const movieratings fc<{}> = ({}) reactelement => { 20 // state variable 21 const \[queryresults, setqueryresults] = usestate(null); 22 const \[ratingsaverage, setratingsaverage] = usestate(''); 23 const \[reviewtext, setreviewtext] = usestate(''); 24 const \[reviewrate, setreviewrate] = usestate(''); 25	 26 const rungetmovieaveragerating = async function () promise\<boolean> { 27 try { 28 const params {movie string} = { 29 movie 'mission very possible', 30 }; 31 let resultobject {result number} = await parse cloud run( 32 'getmovieaveragerating', 33 params, 34 ); 35 // set query results to state variable using state hook 36 setratingsaverage(resultobject result tofixed(1)); 37 return true; 38 } catch (error) { 39 // error can be caused by lack of internet connection 40 // or by not having an valid review object yet 41 alert alert( 42 'error!', 43 'make sure that the cloud function is deployed and that the review class table is created', 44 ); 45 return false; 46 } 47 }; 48	 49 const doreviewquery = async function () promise\<boolean> { 50 // create our query 51 let parsequery parse query = new parse query('review'); 52 try { 53 let results \[parse object] = await parsequery find(); 54 // set query results to state variable 55 setqueryresults(results); 56 return true; 57 } catch (error) { 58 // error can be caused by lack of internet connection 59 alert alert('error!', error message); 60 return false; 61 } 62 }; 63	 64 const createreview = async function () promise\<boolean> { 65 try { 66 // this values come from state variables linked to 67 // the screen form fields 68 const reviewtextvalue string = reviewtext; 69 const reviewratevalue number = number(reviewrate); 70	 71 // creates a new parse object instance 72 let review parse object = new parse object('review'); 73	 74 // set data to parse object 75 // simple title field 76 review\ set('text', reviewtextvalue); 77	 78 // simple number field 79 review\ set('rate', reviewratevalue); 80	 81 // set default movie 82 review\ set('movie', 'mission very possible'); 83	 84 // after setting the values, save it on the server 85 try { 86 await review\ save(); 87 // success 88 alert alert('success!'); 89 // updates query result list 90 doreviewquery(); 91 rungetmovieaveragerating(); 92 return true; 93 } catch (error) { 94 // error can be caused by lack of internet connection 95 alert alert('error!', error message); 96 return false; 97 } 98 } catch (error) { 99 // error can be caused by lack of field values 100 alert alert('error!', error message); 101 return false; 102 } 103 }; 104	 105 return ( 106 <> 107 \<view style={styles header}> 108 \<image 109 style={styles header logo} 110 source={ { 111 uri 112 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png', 113 } } 114 /> 115 \<papertext style={styles header text}> 116 \<papertext style={styles header text bold}> 117 {'react native on back4app '} 118 \</papertext> 119 {' cloud code movie ratings'} 120 \</papertext> 121 \</view> 122 \<scrollview style={styles wrapper}> 123 \<view> 124 \<title>{'mission very possible reviews'}\</title> 125 \<papertext>{`ratings average ${ratingsaverage}`}\</papertext> 126 {/ query list /} 127 {queryresults !== null && 128 queryresults !== undefined && 129 queryresults map((result parse object) => ( 130 \<list item 131 key={result id} 132 title={`review text ${result get('text')}`} 133 description={`rate ${result get('rate')}`} 134 titlestyle={styles list text} 135 style={styles list item} 136 /> 137 ))} 138 {queryresults === null || 139 queryresults === undefined || 140 (queryresults !== null && 141 queryresults !== undefined && 142 queryresults length <= 0) ? ( 143 \<papertext>{'no results here!'}\</papertext> 144 ) null} 145 \</view> 146 \<view> 147 \<title>action buttons\</title> 148 \<paperbutton 149 onpress={() => rungetmovieaveragerating()} 150 mode="contained" 151 icon="search web" 152 color={'#208aec'} 153 style={styles list button}> 154 {'calculate review average'} 155 \</paperbutton> 156 \<paperbutton 157 onpress={() => doreviewquery()} 158 mode="contained" 159 icon="search web" 160 color={'#208aec'} 161 style={styles list button}> 162 {'query reviews'} 163 \</paperbutton> 164 \</view> 165 \<view> 166 \<title>add new review\</title> 167 \<papertextinput 168 value={reviewtext} 169 onchangetext={text => setreviewtext(text)} 170 label="text" 171 mode="outlined" 172 style={styles form input} 173 /> 174 \<papertextinput 175 value={reviewrate} 176 onchangetext={text => setreviewrate(text)} 177 keyboardtype={'number pad'} 178 label="rate (1 5)" 179 mode="outlined" 180 style={styles form input} 181 /> 182 \<paperbutton 183 onpress={() => createreview()} 184 mode="contained" 185 icon="plus" 186 style={styles submit button}> 187 {'add'} 188 \</paperbutton> 189 \</view> 190 \</scrollview> 191 \</> 192 ); 193 }; 194	 195 // these define the screen component styles 196 const styles = stylesheet create({ 197 header { 198 alignitems 'center', 199 paddingtop 30, 200 paddingbottom 50, 201 backgroundcolor '#208aec', 202 }, 203 header logo { 204 height 50, 205 width 220, 206 resizemode 'contain', 207 }, 208 header text { 209 margintop 15, 210 color '#f0f0f0', 211 fontsize 16, 212 }, 213 header text bold { 214 color '#fff', 215 fontweight 'bold', 216 }, 217 wrapper { 218 width '90%', 219 alignself 'center', 220 }, 221 list button { 222 margintop 6, 223 marginleft 15, 224 height 40, 225 }, 226 list item { 227 borderbottomwidth 1, 228 borderbottomcolor 'rgba(0, 0, 0, 0 12)', 229 }, 230 list text { 231 fontsize 15, 232 }, 233 form input { 234 height 44, 235 marginbottom 16, 236 backgroundcolor '#fff', 237 fontsize 14, 238 }, 239 submit button { 240 width '100%', 241 maxheight 50, 242 alignself 'center', 243 backgroundcolor '#208aec', 244 }, 245 }); this is how the component should look like after rendering and querying by one of the query functions conclusion at the end of this guide, you learned how parse cloud code functions work and how to perform them on back4app from a react native app in the next guide, you will learn how to work with users in parse