React Native
...
Data objects
CRUD операций с GraphQL в React Native
16 мин
учебник по crud с использованием react native и graphql введение управление данными на back4app с использованием graphql — это мощный вариант для любого типа приложения, который ускоряет запросы и упрощает самые сложные из них back4app использует общие соглашения для конфигурации graphql и предоставляет отличные инструменты для настройки вашей среды разработки в этом руководстве вы узнаете, как выполнять основные операции с данными через пример приложения crud, который покажет вам, как создавать, читать, обновлять и удалять данные из вашей базы данных сервера parse в react native с использованием graphql и relay сначала вы создадите функции компонентов для каждой операции crud, используя их позже в полном макете экрана, в результате чего получится приложение для списка дел в любое время вы можете получить доступ к этому проекту через наши репозитории на github, чтобы ознакомиться со стилями и полным кодом репозиторий примера на javascript предварительные требования для этого учебника мы будем использовать сервер parse версии 4 4 если вы хотите использовать другие версии, вы можете проверить соответствующий код мутации в https //www back4app com/docs/parse graphql/graphql logout mutation пример для вашей соответствующей версии приложение react native, созданное и подключенное к back4app; завершите учебник по настройке среды relay хорошее понимание relay store и relay connection updater; вы можете прочитать больше на документации relay modern мы будем использовать javascript в качестве реализации по умолчанию цель создать базовое crud приложение на react native с использованием parse, graphql и relay 1 создание класса todo на этом первом этапе нам нужно определить класс, с которым будет работать приложение класс todo todo должен иметь только поле заголовка ( string string ) для описания задачи и поле done ( boolean boolean ) для указания, завершена ли задача вы можете использовать общую мутацию для создания класса в вашей базе данных, если у вас его нет, следуя нашему руководству в graphql cookbook https //www back4app com/docs/parse graphql/graphql mutation create object вы также можете создать класс, используя панель управления back4app, через сам браузер базы данных или из js или graphql консолей после создания этого нового класса не забудьте скачать файл schema json schema json с панели управления и сохранить его в вашем приложении в директории data data это необходимо для того, чтобы компилятор relay автоматически генерировал типы из запросов, мутаций и т д на этом этапе ваша панель управления back4app автоматически сгенерирует crud мутации для объекта класса, чтобы увидеть их, вы можете перейти в консоль graphql, открыть вкладку документации и найти todo todo 2 запрос и отображение объектов теперь давайте создадим компонент, который будет отвечать за выполнение запроса списка на сервере back4app, устанавливая соединение для объектов и автоматически отображая и обновляя содержимое списка по мере его изменения создайте новый файл с именем todolistqueryrenderer js todolistqueryrenderer js в вашем src src каталоге со следующим кодом 1 import react from 'react'; 2 import { view, text } from 'react native'; 3 import { graphql, queryrenderer } from 'react relay'; 4	 5 // prerequisite properly configured relay environment 6 import environment from ' / /relay/environment'; 7	 8 // this will be created in the next steps 9 import todolist from ' /todolist'; 10	 11 const todolistqueryrenderer = () => { 12 return ( 13 // the queryrenderer acts as a wrapper to any code, providing query results to 14 // the child components and updating them as needed 15 // note that the query is using a fragment called todolist query, 16 // which will be created in the next steps 17 \<queryrenderer 18 environment={environment} 19 query={graphql` 20 query todolistqueryrendererquery { 21 todolist query 22 } 23 `} 24 variables={null} 25 render={({ error, props }) => { 26 if (error) { 27 return ( 28 \<view> 29 \<text>{error message}\</text> 30 \</view> 31 ); 32 } else if (props) { 33 return \<todolist query={props} />; 34 } 35 return ( 36 \<view> 37 \<text>loading \</text> 38 \</view> 39 ); 40 }} 41 /> 42 ); 43 } 44	 45 export default todolistqueryrenderer; 3 создайте компонент списка и фрагмент объекта теперь давайте создадим наш компонент списка, который будет отображать данные, полученные от queryrenderer на данный момент компонент будет содержать только простое прокручиваемое представление, содержащее функцию map, отображающую каждый узел создайте новый файл в вашем каталоге src с именем todolist js todolist js и добавьте следующий код 1 import react, {usestate} from 'react'; 2 import { 3 view, 4 safeareaview, 5 image, 6 scrollview, 7 statusbar, 8 stylesheet, 9 touchableopacity, 10 } from 'react native'; 11	 12 import { 13 list, 14 text as papertext, 15 button as paperbutton, 16 textinput as papertextinput, 17 } from 'react native paper'; 18 import {createfragmentcontainer} from 'react relay'; 19	 20 const todolist = props => { 21 const \[newtodotitle, setnewtodotitle] = usestate(''); 22	 23 const {query} = props; 24 const {todos} = query; 25	 26 const rendertodos = () => { 27 if (!todos) { 28 return null; 29 } 30	 31 return todos edges map(({node todo}) => ( 32 \<list item 33 key={todo id} 34 title={todo title} 35 titlestyle={todo done ? styles todo text done styles todo text} 36 style={styles todo item} 37 right={props => ( 38 <> 39 {!todo done && ( 40 \<touchableopacity onpress={() => updatetodo(todo id, true)}> 41 \<list icon { props} icon="check" color={'#4caf50'} /> 42 \</touchableopacity> 43 )} 44	 45 \<touchableopacity onpress={() => deletetodo(todo id)}> 46 \<list icon { props} icon="close" color={'#ef5350'} /> 47 \</touchableopacity> 48 \</> 49 )} 50 /> 51 )); 52 }; 53	 54 return ( 55 <> 56 \<statusbar backgroundcolor="#208aec" /> 57 \<safeareaview style={styles container}> 58 \<view style={styles header}> 59 \<papertext style={styles header text bold}> 60 {'react native on back4app'} 61 \</papertext> 62 \<papertext style={styles header text}>{'product creation'}\</papertext> 63 \</view> 64 \<view style={styles create todo container}> 65 \</view> 66 \<scrollview style={styles todo list}>{rendertodos()}\</scrollview> 67 \</safeareaview> 68 \</> 69 ); 70 }; 71	 72 const todolistfragmentcontainer = createfragmentcontainer(todolist, { 73 query graphql` 74 fragment todolist query on query { 75 todos(first 50) @connection(key "todolist todos", filters \[]) { 76 edges { 77 node { 78 id 79 title 80 done 81 } 82 } 83 } 84 } 85 `, 86 }); рендерер запросов на шаге 2 ожидает фрагмент данных с именем todolist query todolist query , поэтому мы добавили его в компонент списка в конце файла помните, что фрагменты graphql — это структуры, отвечающие за вызов данных, необходимых компонентам для рендеринга, и за указание того, что должно быть возвращено 4 создание объектов первый шаг к управлению вашими данными в вашей базе данных graphql back4app — это наличие данных в ней нам нужно создать функцию, чтобы вызвать создание нового todo todo в нашем компоненте списка, используя мутацию, отвечающую за это давайте начнем с мутации, поэтому создайте новый файл с именем createtodomutation js createtodomutation js в директории src/mutations src/mutations , содержащей следующий код 1 import { commitmutation, graphql } from "react relay"; 2 import { root id, connectionhandler } from 'relay runtime'; 3	 4 const connectioncreateedgeupdater = (store, nodeid) => { 5 const parentproxy = store get(root id); 6 const todoconnection = connectionhandler getconnection(parentproxy, 'todolist todos'); 7	 8 const newtodo = store get(nodeid); 9 const edge = connectionhandler createedge(store, todoconnection, newtodo, 'todoedge'); 10 11 // no cursor provided, append the edge at the end 12 connectionhandler insertedgeafter(todoconnection, edge); 13 } 14	 15 const mutation = graphql` 16 mutation createtodomutation($input createtodoinput!) { 17 createtodo(input $input) { 18 todo { 19 id 20 title 21 done 22 } 23 } 24 } 25 `; 26	 27 function commit({ environment, input, oncompleted, onerror }) { 28 const variables = { input }; 29	 30 commitmutation(environment, { 31 mutation, 32 variables, 33 oncompleted, 34 onerror, 35 updater (store) => { 36 const todoid = store getrootfield('createtodo') getlinkedrecord('todo') getvalue('id'); 37	 38 connectioncreateedgeupdater(store, todoid) 39 } 40 }); 41 } relay modern предоставляет нам множество api эндпоинтов, которые можно использовать для обновления данных после вызовов мутаций в этой функции мы использовали некоторые из его функций, чтобы получить новый todo todo и обновить уже существующий список на фронтенде с таким подходом мы избегаем нового вызова к бэкенду, экономя время, которое было бы потрачено на новый запрос, интернет пользователя, избыточные данные и многое другое теперь добавьте следующую функцию в компонент todolist todolist , которая вызовет createtodomutation createtodomutation и будет ссылаться на нее позже через кнопку 1 const createtodo = () => { 2 const input = { 3 fields { 4 title newtodotitle, 5 done false, 6 }, 7 }; 8	 9 createtodomutation commit({ 10 environment, 11 input input, 12 oncompleted () => { 13 alert alert('success!', 'todo created!'); 14 setnewtodotitle(''); 15 }, 16 onerror (errors) => { 17 alert alert('error!', errors); 18 }, 19 }); 20 } 5 обновление объектов обновление объекта похоже на его создание, с добавлением того, что, когда вы обновляете объект с помощью relay modern, вам просто нужно запросить поля, которые вы хотите обновить с новым состоянием на выходе мутации создайте новый файл с именем updatetodomutation js updatetodomutation js в директории src/mutations src/mutations с следующим кодом 1 import { commitmutation, graphql } from "react relay"; 2	 3 const mutation = graphql` 4 mutation updatetodomutation($input updatetodoinput!) { 5 updatetodo(input $input) { 6 todo { 7 id 8 title 9 done 10 } 11 } 12 } 13 `; 14	 15 function commit({ environment, input, oncompleted, onerror }) { 16 const variables = { input }; 17	 18 commitmutation(environment, { 19 mutation, 20 variables, 21 oncompleted, 22 onerror, 23 }); 24 } 25	 26 export default { 27 commit, 28 }; так же, как и на предыдущем шаге, добавьте следующую функцию в компонент todolist todolist , которая вызовет updatetodomutation updatetodomutation , и на которую будет ссылаться кнопка 1 const updatetodo = (todoid, done) => { 2 const input = { 3 id todoid, 4 fields { 5 done, 6 } 7 } 8	 9 updatetodomutation commit({ 10 environment, 11 input input, 12 oncompleted () => { 13 alert alert('success!', 'todo updated!'); 14 }, 15 onerror (errors) => { 16 alert alert('error!', errors); 17 }, 18 }); 19 } 6 удаление объектов когда вы удаляете объект, с помощью api relay store вы можете обновить список и удалить старый объект с фронтенда мы вызовем колбек обновления, аналогичный обновлению из createtodo createtodo , но мы передадим соединение и идентификатор задачи, чтобы удалить ее из списка таким образом, мы поддерживаем фронтенд в актуальном состоянии с нашим сервером создайте новый файл с именем deletetodomutation js deletetodomutation js в директории src/mutations src/mutations с следующим кодом 1 import { commitmutation, graphql } from "react relay"; 2 import { root id, connectionhandler } from 'relay runtime'; 3	 4 const connectiondeleteedgeupdater = (store, nodeid) => { 5 const parentproxy = store get(root id); 6 const connection = connectionhandler getconnection(parentproxy, 'todolist todos'); 7	 8 const newcount = connection getvalue('count'); 9 connection setvalue(newcount 1, 'count'); 10	 11 connectionhandler deletenode(connection, nodeid); 12 } 13	 14 const mutation = graphql` 15 mutation deletetodomutation($input deletetodoinput!) { 16 deletetodo(input $input) { 17 todo { 18 id 19 } 20 } 21 } 22 `; 23	 24 function commit({ environment, input, oncompleted, onerror }) { 25 const variables = { input }; 26	 27 commitmutation(environment, { 28 mutation, 29 variables, 30 oncompleted, 31 onerror, 32 updater (store) => { 33 connectiondeleteedgeupdater(store, input id) 34 } 35 }); 36 } 37	 38 export default { 39 commit, 40 }; так же, как и на предыдущем шаге, добавьте следующую функцию в компонент todolist todolist , которая вызовет deletetodomutation deletetodomutation и будет ссылаться на нее позже через кнопку 1 const deletetodo = (todoid) => { 2 const input = { 3 id todoid, 4 } 5	 6 deletetodomutation commit({ 7 environment, 8 input input, 9 oncompleted () => { 10 alert alert('success!', 'todo deleted!'); 11 }, 12 onerror (errors) => { 13 alert alert('error!', errors); 14 }, 15 }); 16 } 7 использование crud в компоненте react native теперь давайте завершим наш todolist todolist код компонента с оформленными элементами пользовательского интерфейса, переменными состояния и вызовами ваших crud функций 1 import react, {usestate} from 'react'; 2 import { 3 alert, 4 view, 5 safeareaview, 6 image, 7 scrollview, 8 statusbar, 9 stylesheet, 10 touchableopacity, 11 } from 'react native'; 12	 13 import { 14 list, 15 text as papertext, 16 button as paperbutton, 17 textinput as papertextinput, 18 } from 'react native paper'; 19 import {createfragmentcontainer} from 'react relay'; 20 import createtodomutation from ' /mutations/createtodomutation'; 21 import updatetodomutation from ' /mutations/updatetodomutation'; 22 import deletetodomutation from ' /mutations/deletetodomutation'; 23	 24 import environment from ' / /relay/environment'; 25	 26 const todolist = props => { 27 const \[newtodotitle, setnewtodotitle] = usestate(''); 28	 29 const {query} = props; 30 const {todos} = query; 31	 32 const createtodo = () => { 33 const input = { 34 fields { 35 title newtodotitle, 36 done false, 37 }, 38 }; 39	 40 createtodomutation commit({ 41 environment, 42 input input, 43 oncompleted () => { 44 alert alert('success!', 'todo created!'); 45 setnewtodotitle(''); 46 }, 47 onerror errors => { 48 alert alert('error!', errors); 49 }, 50 }); 51 }; 52	 53 const updatetodo = (todoid, done) => { 54 const input = { 55 id todoid, 56 fields { 57 done, 58 }, 59 }; 60	 61 updatetodomutation commit({ 62 environment, 63 input input, 64 oncompleted () => { 65 alert alert('success!', 'todo updated!'); 66 }, 67 onerror errors => { 68 alert alert('error!', errors); 69 }, 70 }); 71 }; 72	 73 const deletetodo = todoid => { 74 const input = { 75 id todoid, 76 }; 77	 78 deletetodomutation commit({ 79 environment, 80 input input, 81 oncompleted () => { 82 alert alert('success!', 'todo deleted!'); 83 }, 84 onerror errors => { 85 alert alert('error!', errors); 86 }, 87 }); 88 }; 89	 90 const rendertodos = () => { 91 if (!todos) { 92 return null; 93 } 94	 95 return todos edges map(({node todo}) => ( 96 \<list item 97 key={todo id} 98 title={todo title} 99 titlestyle={todo done ? styles todo text done styles todo text} 100 style={styles todo item} 101 right={props => ( 102 <> 103 {!todo done && ( 104 \<touchableopacity onpress={() => updatetodo(todo id, true)}> 105 \<list icon { props} icon="check" color={'#4caf50'} /> 106 \</touchableopacity> 107 )} 108	 109 \<touchableopacity onpress={() => deletetodo(todo id)}> 110 \<list icon { props} icon="close" color={'#ef5350'} /> 111 \</touchableopacity> 112 \</> 113 )} 114 /> 115 )); 116 }; 117	 118 return ( 119 <> 120 \<statusbar backgroundcolor="#208aec" /> 121 \<safeareaview style={styles container}> 122 \<view style={styles header}> 123 \<image 124 style={styles header logo} 125 source={ { 126 uri 127 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png', 128 } } 129 /> 130 \<papertext style={styles header text bold}> 131 {'react native on back4app'} 132 \</papertext> 133 \<papertext style={styles header text}>{'product creation'}\</papertext> 134 \</view> 135 \<view style={styles create todo container}> 136 {/ todo create text input /} 137 \<papertextinput 138 value={newtodotitle} 139 onchangetext={text => setnewtodotitle(text)} 140 label="new todo" 141 mode="outlined" 142 style={styles create todo input} 143 /> 144 {/ todo create button /} 145 \<paperbutton 146 onpress={() => createtodo()} 147 mode="contained" 148 icon="plus" 149 color={'#208aec'} 150 style={styles create todo button}> 151 {'add'} 152 \</paperbutton> 153 \</view> 154 \<scrollview style={styles todo list}>{rendertodos()}\</scrollview> 155 \</safeareaview> 156 \</> 157 ); 158 }; 159	 160 const todolistfragmentcontainer = createfragmentcontainer(todolist, { 161 query graphql` 162 fragment todolist query on query { 163 todos(first 1000) @connection(key "todolist todos", filters \[]) { 164 edges { 165 node { 166 id 167 title 168 done 169 } 170 } 171 } 172 } 173 `, 174 }); 175	 176 const styles = stylesheet create({ 177 container { 178 flex 1, 179 backgroundcolor '#fff', 180 }, 181 wrapper { 182 width '90%', 183 alignself 'center', 184 }, 185 header { 186 alignitems 'center', 187 paddingtop 10, 188 paddingbottom 20, 189 backgroundcolor '#208aec', 190 }, 191 header logo { 192 width 170, 193 height 40, 194 marginbottom 10, 195 resizemode 'contain', 196 }, 197 header text bold { 198 color '#fff', 199 fontsize 14, 200 fontweight 'bold', 201 }, 202 header text { 203 margintop 3, 204 color '#fff', 205 fontsize 14, 206 }, 207 flex between { 208 flexdirection 'row', 209 alignitems 'center', 210 justifycontent 'space between', 211 }, 212 create todo container { 213 flexdirection 'row', 214 paddingleft 10, 215 paddingright 10, 216 }, 217 create todo input { 218 flex 1, 219 height 38, 220 marginbottom 16, 221 backgroundcolor '#fff', 222 fontsize 14, 223 }, 224 create todo button { 225 margintop 6, 226 marginleft 15, 227 height 40, 228 }, 229 todo list { 230 paddingleft 10, 231 paddingright 10, 232 }, 233 todo item { 234 borderbottomwidth 1, 235 borderbottomcolor 'rgba(0, 0, 0, 0 12)', 236 }, 237 todo text { 238 fontsize 15, 239 }, 240 todo text done { 241 color 'rgba(0, 0, 0, 0 3)', 242 fontsize 15, 243 textdecorationline 'line through', 244 }, 245 }); 246	 247 export default todolistfragmentcontainer; перед запуском вашего проекта не забудьте запустить yarn relay yarn relay и обновить типы relay generated generated если ваш компонент правильно настроен, вы должны увидеть что то подобное после сборки и запуска приложения продолжайте и добавьте несколько задач, вводя их названия в поле ввода по одной и нажимая кнопку добавить обратите внимание, что после каждого успешного создания функция createtodo createtodo вызывает колбек обновления в мутации, автоматически обновляя ваш список задач теперь у вас должен быть значительный список задач, похожий на этот теперь вы можете пометить свои задачи как выполненные, нажав на галочку рядом с ней, что приведет к обновлению значения выполненности на true и изменению статуса иконки слева как было сказано на этапе функции обновления, relay автоматически обновит todo с новым значением поля выполнено выполнено единственной оставшейся операцией с данными теперь является удаление, которое можно выполнить, нажав на иконку мусорной корзины в самом правом углу вашего объекта списка дел после успешного удаления объекта вы должны получить сообщение об оповещении, подобное этому заключение в конце этого руководства вы узнали, как выполнять основные операции с данными (crud) с помощью grapqhql и relay modern на react native, а также изучили api соединений relay, которые помогают нам обновлять наш фронтенд