React Native
...
Cloud Functions
Интеграция Parse Cloud Functions в React Native
15 мин
использование облачных функций в приложении react native введение в этом руководстве вы узнаете, как использовать функции облачного кода parse из приложения react native вы увидите примеры триггеров, реализованных с помощью облачных функций, а также узнаете, как реализовать компонент react native, используя эти функции и back4app предварительные требования чтобы завершить это руководство, вам потребуется созданное приложение react native и https //www back4app com/docs/react native/parse sdk/react native sdk понимание того, как https //www back4app com/docs/get started/cloud functions на back4app если вы хотите запустить пример приложения из этого руководства, вам следует установить react native paper react native paper https //github com/callstack/react native paper цель запуск облачного кода parse на back4app из приложения react native 1 понимание функций облачного кода в ваших приложениях будут случаи, когда вам нужно будет выполнять определенные операции с данными или тяжелую обработку, которые не следует выполнять на мобильных устройствах в таких случаях вы можете использовать функции облачного кода, которые выполняются непосредственно на вашем сервере parse и вызываются с помощью api parse обратите внимание, что это также позволяет изменять некоторые части логики вашего приложения без необходимости выпускать новую версию в магазинах приложений, что может быть полезно в некоторых случаях существует два основных типа функций облачного кода общие функции, использующие 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 }); ответ 1 { "result" 3 5 } сохранить триггеры 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 использование cloud code из компонента react native теперь давайте создадим пример функции parse cloud code и вызовем ее внутри компонента в react native, с простым интерфейсом, имеющим метку, показывающую результат функции, а также форму для добавления новых объектов наша облачная функция будет вычислять среднее значение оценок каждого фильма review review объекта в нашем приложении, который является parse object parse object классом, состоящим из text text , rate rate и movie movie полей вот код функции 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 и как выполнять их на back4app из приложения react native в следующем руководстве вы узнаете, как работать с пользователями в parse