React Native
...
Data objects
리액트 네이티브와 GraphQL을 통한 고급 CRUD 구현
15 분
리액트 네이티브 graphql crud 튜토리얼 소개 graphql을 사용하여 back4app에서 데이터를 관리하는 것은 모든 유형의 애플리케이션에 강력한 옵션으로, 쿼리를 가속화하고 가장 복잡한 쿼리를 단순화합니다 back4app은 graphql 구성에 대한 일반적인 규칙을 사용하며 개발 환경 설정을 돕기 위한 훌륭한 도구를 제공합니다 이 가이드에서는 crud 예제 앱을 통해 기본 데이터 작업을 수행하는 방법을 배우게 되며, 이를 통해 react native에서 graphql과 relay를 사용하여 parse 서버 데이터베이스에서 데이터를 생성, 읽기, 업데이트 및 삭제하는 방법을 보여줍니다 먼저 각 crud 작업에 대한 구성 요소 함수를 생성한 후, 이를 전체 화면 레이아웃에서 사용하여 할 일 목록 앱을 만들 것입니다 언제든지 github 리포지토리를 통해 이 프로젝트에 접근하여 스타일과 전체 코드를 확인할 수 있습니다 자바스크립트 예제 리포지토리 사전 요구 사항 이 튜토리얼에서는 4 4 버전의 parse server를 사용할 것입니다 다른 버전을 사용하고 싶다면 https //www back4app com/docs/parse graphql/graphql logout mutation 의 해당 변형 코드를 확인할 수 있습니다 back4app에 생성되고 연결된 리액트 네이티브 앱; 다음의 relay 환경 설정 튜토리얼 relay store 및 relay connection updater에 대한 좋은 이해; relay 현대 문서 기본 구현으로 자바스크립트를 사용할 것입니다 목표 parse, graphql 및 relay를 사용하여 react native에서 기본 crud 애플리케이션을 구축합니다 1 todo 클래스 생성 이 첫 번째 단계에서는 애플리케이션이 작동할 클래스를 정의해야 합니다 todo todo 클래스는 작업을 설명하는 제목( string string ) 필드와 작업이 완료되었는지를 나타내는 done( boolean boolean ) 필드만 필요합니다 클래스가 없다면, graphql 요리책 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에서 가져온 데이터를 렌더링할 목록 구성 요소를 만들어 보겠습니다 이 구성 요소는 현재 각 노드를 렌더링하는 맵 기능을 포함하는 간단한 스크롤 뷰만 포함할 것입니다 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 객체 생성하기 back4app graphql 데이터베이스에서 데이터를 관리하는 첫 번째 단계는 그 위에 데이터를 갖는 것입니다 우리는 이를 위해 새로운 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 객체 삭제하기 객체를 삭제할 때, relay store api를 사용하여 목록을 업데이트하고 프론트엔드에서 오래된 객체를 제거할 수 있습니다 우리는 createtodo createtodo 와 유사한 업데이트 콜백을 호출할 것입니다 하지만 목록에서 제거할 할 일의 연결과 id를 전달할 것입니다 이렇게 하면 프론트엔드가 서버에 충실하게 업데이트됩니다 다음 코드를 포함하는 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 react native 컴포넌트에서 crud 사용하기 이제 스타일이 적용된 사용자 인터페이스 요소, 상태 변수 및 crud 함수 호출로 todolist todolist 구성 요소 코드를 완성합시다 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 함수가 mutation의 업데이트 콜백을 트리거하여 작업 목록을 자동으로 새로 고칩니다 이제 다음과 같은 상당한 할 일 목록이 있어야 합니다 이제 체크마크를 클릭하여 작업을 완료로 표시할 수 있으며, 이로 인해 완료 값이 true로 업데이트되고 왼쪽의 아이콘 상태가 변경됩니다 업데이트 함수 단계에서 언급한 바와 같이, relay는 필드의 새 값으로 todo를 자동으로 업데이트합니다 완료 완료 이제 남은 데이터 작업은 삭제 작업뿐이며, 이는 할 일 목록 객체의 가장 오른쪽에 있는 쓰레기통 아이콘을 눌러 수행할 수 있습니다 객체를 성공적으로 삭제한 후에는 다음과 같은 경고 메시지를 받아야 합니다 결론 이 가이드를 마치면서, react native에서 grapqhql과 relay modern을 사용하여 기본 데이터 작업(crud)을 수행하는 방법과 프론트엔드를 업데이트하는 데 도움이 되는 relay connection api에 대해 배웠습니다