React Native
...
Cloud Functions
在React Native中使用Parse云代码实现开发
14 分
在 react native 应用中使用云函数 介绍 在本指南中,您将学习如何从 react native 应用中使用 parse 云代码函数。您将看到使用云函数实现的触发器示例,并检查如何使用这些函数和 back4app 实现 react native 组件。 先决条件 要完成本教程,您需要: 一个已创建并 连接到 back4app 的 react native 应用 了解如何在 back4app 上部署云函数 如果您想运行本指南的示例应用,您应该设置 react native paper react native paper 库 目标 从 react native 应用中在 back4app 上运行 parse 云代码。 1 理解云代码函数 在您的应用中,有时您需要执行某些数据操作或重处理,这些操作不应在移动设备上进行。在这些情况下,您可以使用云代码函数,这些函数直接在您的 parse 服务器上运行,并通过 parse api 调用。请注意,这也使您能够在不需要在应用商店发布新版本的情况下更改应用逻辑的某些部分,这在某些情况下可能很有用。 云代码函数主要有两种类型,通用函数,使用 define define 并持有您想要的任何类型的代码,以及在 parse 服务器上自动触发的触发器,这些触发器在特定事件发生时被触发。 在下一步中,您将看到大多数这些功能类型的示例,这些示例可以直接在您的 back4app 仪表板或通过 cli 创建和部署。您可以查看如何在 我们的云函数入门指南 https //www back4app com/docs/get started/cloud functions 中执行此操作。 2 云代码参考 云函数 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 }); 响应: 保存触发器 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 }); 删除触发器 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 }); 文件触发器 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 }); 查找触发器 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 }); 会话触发器 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 从 react native 组件使用云代码 现在让我们创建一个示例 parse 云代码函数,并在 react native 中的组件内调用它,界面简单,包含一个显示函数结果的标签和一个添加新对象的表单。 我们的云函数将计算我们应用中每部电影的评分平均值, 评论 评论 对象,这是一个由 parse object parse object 类组成的,包含 文本 文本 , 评分 评分 和 电影 电影 字段。以下是函数代码: 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 }); 要在 react native 中调用此云函数,您需要使用 parse cloud run parse cloud run 方法,将函数名称和任何必要的参数作为对象传递。 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 }; 我们还可以通过为 beforesave beforesave 触发函数来强制评论文本保持简短,适用于 review review 对象。以下是函数代码: 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 }); 这就是完整组件代码的布局方式: 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 }); 组件在渲染和通过查询函数之一查询后应该是这样的: 结论 在本指南的最后,您了解了 parse cloud code 函数的工作原理,以及如何从 react native 应用程序在 back4app 上执行它们。在下一个指南中,您将学习如何在 parse 中处理用户。