React Native
...
Cloud Functions
Интеграция Parse Cloud Functions в React Native
15 мин
использование облачных функций в приложении react native введение в этом руководстве вы узнаете, как использовать функции облачного кода parse из приложения react native вы увидите примеры триггеров, реализованных с помощью облачных функций, а также узнаете, как реализовать компонент react native, используя эти функции и back4app предварительные требования чтобы завершить это руководство, вам потребуется созданное приложение react native и подключенное к back4app понимание того, как развернуть облачную функцию на back4app если вы хотите запустить пример приложения из этого руководства, вам следует установить react native paper 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 }); ответ сохранить триггеры 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