ReactJS
Users
리액트에서 페이스북 로그인 구현: 개발자 가이드
10 분
리액트 페이스북 로그인 소개 지난 튜토리얼에서는 parse user parse user 클래스를 사용하여 앱에 사용자 로그인/로그아웃 기능을 추가했습니다 이제 페이스북 로그인을 사용하여 페이스북에서 사용자 데이터를 가져오고, 로그인하거나 가입하거나 기존 사용자와 연결하는 방법을 배울 것입니다 또한 이를 달성하기 위해 react facebook login react facebook login 라이브러리를 설치하고 구성할 것입니다 parse user linkwith parse user linkwith 메서드는 각기 다른 제공자가 요청하는 올바른 매개변수를 전달하는 한, 모든 서드파티 인증 방법을 사용하여 사용자를 가입시키고 로그인시키는 역할을 합니다 사용자 데이터를 새 또는 기존 parse user parse user 에 연결한 후, parse는 귀하의 장치에 유효한 사용자 세션을 저장합니다 이후 current current 과 같은 메서드를 호출하면 일반 로그인과 마찬가지로 사용자 데이터를 성공적으로 검색할 수 있습니다 전제 조건 이 튜토리얼을 완료하려면 다음이 필요합니다 react 앱이 생성되고 back4app에 연결됨 이전 가이드를 완료하여 parse user 클래스와 parse user login 메서드에 대한 더 나은 이해를 가질 수 있습니다 https //www back4app com/docs/react/working with users/react user login 이 가이드에서 제공하는 화면 레이아웃을 테스트/사용하려면 ant design ant design 라이브러리를 설정해야 합니다 목표 react 앱에서 parse를 사용하여 facebook 로그인을 통한 사용자 로그인 기능을 구축합니다 1 의존성 설치 react에서 facebook 로그인을 활성화하는 가장 인기 있는 방법은 react facebook login react facebook login 을 사용하는 것입니다 공식 문서 를 따라 설정하세요 lib 구성 요소를 사용하려면 유효한 facebook 앱 appid appid , 을 알려야 하므로, facebook for developers 대시보드에서 하나를 생성하세요 그들의 공식 가이드 그 후, 앱에 facebook 로그인 기능을 추가하고 www 옵션을 선택하여 https //localhost 3000 https //localhost 3000 을 웹사이트 url로 입력하세요 facebook 로그인을 사용하려면 연결이 안전해야 하며, 개발 환경에서 로그인할 때도 마찬가지입니다 따라서 로컬 인증서를 생성하고, 운영 체제에서 전체 권한을 부여하고, 파일을 프로젝트에 추가하여 react 앱에 https 액세스를 설정해야 합니다 각 운영 체제마다 특성이 다를 수 있으므로, 이 가이드에서는 다루지 않습니다 인증서를 생성한 후, scripts scripts 세션에서 package json package json 파일의 시작 명령을 다음과 같이 변경하세요 1 "start" "export https=true&\&ssl crt file=cert pem&\&ssl key file=key pem react scripts start", typescript를 사용하는 경우, src src 폴더에 react facebook login d ts react facebook login d ts 라는 새 파일을 생성하고, react facebook login react facebook login 모듈 선언을 포함하여 스타일 없는 버전을 사용하세요 react facebook login d ts 1 declare module 'react facebook login/dist/facebook login render props'; 2 파스와 함께 페이스북 로그인 사용하기 이제 facebook 로그인 인증 모달을 호출할 때 응답을 처리할 새로운 메서드를 userlogin userlogin 컴포넌트 안에 생성해 보겠습니다 사용자가 facebook으로 로그인하면 이 호출은 facebook에서 사용자 데이터를 검색하고 id id , accesstoken accesstoken , 그리고 프로필 email email 그런 다음, 이 함수는 parse user linkwith parse user linkwith 메서드와 이러한 자격 증명을 사용하여 parse에 로그인하려고 시도합니다 사용자가 이미 이 facebook 인증을 사용하여 가입한 경우, linkwith linkwith 는 기존 계정을 사용하여 그를 로그인시킬 것입니다 javascript 1 const handlefacebookloginloginresponse = async function(response) { 2 // check if response has an error 3 if (response error !== undefined) { 4 console log(`error ${response error}`); 5 return false; 6 } else { 7 try { 8 // gather facebook user info 9 const userid = response id; 10 const useremail = response email; 11 const useraccesstoken = response accesstoken; 12 // try to login on parse using linkwith and these credentials 13 // create a new parse user object 14 const usertologin = new parse user(); 15 // set username and email to match facebook profile email 16 usertologin set('username', useremail); 17 usertologin set('email', useremail); 18 try { 19 let loggedinuser = await usertologin 20 linkwith('facebook', { 21 authdata {id userid, access token useraccesstoken}, 22 }); 23 // login returns the corresponding parseuser object 24 alert( 25 `success! user ${loggedinuser get('username')} has successfully signed in!`, 26 ); 27 // update state variable holding current user 28 getcurrentuser(); 29 return true; 30 } catch (error) { 31 // error can be caused by wrong parameters or lack of internet connection 32 alert(`error! ${error message}`); 33 return false; 34 } 35 } catch (error) { 36 console log("error gathering facebook user info, please try again!") 37 return false; 38 } 39 } 40 }1 const handlefacebookloginloginresponse = async function(response any) promise\<boolean> { 2 // check if response has an error 3 if (response error !== undefined) { 4 console log(`error ${response error}`); 5 return false; 6 } else { 7 try { 8 // gather facebook user info 9 const userid string = response id; 10 const useremail string = response email; 11 const useraccesstoken string = response accesstoken; 12 // try to login on parse using linkwith and these credentials 13 // create a new parse user object 14 const usertologin parse user = new parse user(); 15 // set username and email to match facebook profile email 16 usertologin set('username', useremail); 17 usertologin set('email', useremail); 18 try { 19 let loggedinuser parse user = await usertologin 20 linkwith('facebook', { 21 authdata {id userid, access token useraccesstoken}, 22 }); 23 // login returns the corresponding parseuser object 24 alert( 25 `success! user ${loggedinuser get('username')} has successfully signed in!`, 26 ); 27 // update state variable holding current user 28 getcurrentuser(); 29 return true; 30 } catch (error any) { 31 // error can be caused by wrong parameters or lack of internet connection 32 alert(`error! ${error message}`); 33 return false; 34 } 35 } catch (error any) { 36 console log("error gathering facebook user info, please try again!") 37 return false; 38 } 39 } 40 } 그 후, react facebook login react facebook login facebooklogin facebooklogin 컴포넌트를 사용하여 facebook 로그인 모달을 호출하고, 이를 jsx 코드에 추가해야 합니다 facebook의 기본 스타일을 사용하거나 이 가이드에서 따르는 방법처럼 사용자 정의 스타일을 만들 수 있습니다 다음은 전체 userlogin userlogin 컴포넌트 코드입니다 react facebook login react facebook login 버튼과 그것이 이전에 생성된 모달 응답 메서드와 어떻게 연결되어 있는지 주목하세요 javascript 1 import react, { usestate } from 'react'; 2 import parse from 'parse/dist/parse min js'; 3 import facebooklogin from 'react facebook login/dist/facebook login render props'; 4 import ' /app css'; 5 import { button, divider, input } from 'antd'; 6	 7 export const userlogin = () => { 8 // state variables 9 const \[username, setusername] = usestate(''); 10 const \[password, setpassword] = usestate(''); 11 const \[currentuser, setcurrentuser] = usestate(null); 12	 13 const douserlogin = async function () { 14 // note that these values come from state variables that we've declared before 15 const usernamevalue = username; 16 const passwordvalue = password; 17 try { 18 const loggedinuser = await parse user login(usernamevalue, passwordvalue); 19 // login returns the corresponding parseuser object 20 alert( 21 `success! user ${loggedinuser get( 22 'username' 23 )} has successfully signed in!` 24 ); 25 // to verify that this is in fact the current user, `current` can be used 26 const currentuser = await parse user current(); 27 console log(loggedinuser === currentuser); 28 // clear input fields 29 setusername(''); 30 setpassword(''); 31 // update state variable holding current user 32 getcurrentuser(); 33 return true; 34 } catch (error) { 35 // error can be caused by wrong parameters or lack of internet connection 36 alert(`error! ${error message}`); 37 return false; 38 } 39 }; 40	 41 const douserlogout = async function () { 42 try { 43 await parse user logout(); 44 // to verify that current user is now empty, currentasync can be used 45 const currentuser = await parse user current(); 46 if (currentuser === null) { 47 alert('success! no user is logged in anymore!'); 48 } 49 // update state variable holding current user 50 getcurrentuser(); 51 return true; 52 } catch (error) { 53 alert(`error! ${error message}`); 54 return false; 55 } 56 }; 57	 58 // function that will return current user and also update current username 59 const getcurrentuser = async function () { 60 const currentuser = await parse user current(); 61 // update state variable holding current user 62 setcurrentuser(currentuser); 63 return currentuser; 64 }; 65	 66 const handlefacebookloginloginresponse = async function (response) { 67 // check if response has an error 68 if (response error !== undefined) { 69 console log(`error ${response error}`); 70 return false; 71 } else { 72 try { 73 // gather facebook user info 74 const userid = response id; 75 const useremail = response email; 76 const useraccesstoken = response accesstoken; 77 // try to login on parse using linkwith and these credentials 78 // create a new parse user object 79 const usertologin = new parse user(); 80 // set username and email to match facebook profile email 81 usertologin set('username', useremail); 82 usertologin set('email', useremail); 83 try { 84 let loggedinuser = await usertologin linkwith('facebook', { 85 authdata { id userid, access token useraccesstoken }, 86 }); 87 // login returns the corresponding parseuser object 88 alert( 89 `success! user ${loggedinuser get( 90 'username' 91 )} has successfully signed in!` 92 ); 93 // update state variable holding current user 94 getcurrentuser(); 95 return true; 96 } catch (error) { 97 // error can be caused by wrong parameters or lack of internet connection 98 alert(`error! ${error message}`); 99 return false; 100 } 101 } catch (error) { 102 console log('error gathering facebook user info, please try again!'); 103 return false; 104 } 105 } 106 }; 107	 108 return ( 109 \<div> 110 \<div classname="header"> 111 \<img 112 classname="header logo" 113 alt="back4app logo" 114 src={ 115 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png' 116 } 117 /> 118 \<p classname="header text bold">{'react on back4app'}\</p> 119 \<p classname="header text">{'user login'}\</p> 120 \</div> 121 {currentuser === null && ( 122 \<div classname="container"> 123 \<h2 classname="heading">{'user login'}\</h2> 124 \<divider /> 125 \<div classname="form wrapper"> 126 \<input 127 value={username} 128 onchange={(event) => setusername(event target value)} 129 placeholder="username" 130 size="large" 131 classname="form input" 132 /> 133 \<input 134 value={password} 135 onchange={(event) => setpassword(event target value)} 136 placeholder="password" 137 size="large" 138 type="password" 139 classname="form input" 140 /> 141 \</div> 142 \<div classname="form buttons"> 143 \<button 144 onclick={() => douserlogin()} 145 type="primary" 146 classname="form button" 147 color={'#208aec'} 148 size="large" 149 block 150 > 151 log in 152 \</button> 153 \</div> 154 \<divider /> 155 \<div classname="login social"> 156 \<facebooklogin 157 appid="4573670722644997" 158 fields="email" 159 callback={handlefacebookloginloginresponse} 160 render={(renderprops) => ( 161 \<div classname="login social item login social item facebook"> 162 \<img onclick={renderprops onclick} classname="login social item image" src={'https //findicons com/files/icons/2830/clean social icons/250/facebook png'} alt=""/> 163 \</div> 164 )} 165 /> 166 \<div classname="login social item"> 167 \<img classname="login social item image" src={'data\ image/png;base64,ivborw0kggoaaaansuheugaaan8aaadicamaaad5w+jtaaabwvbmvex////qqzu0qfnchft7vauufppk7f08gvr0o/zzofb7uqd7uadpncp/vqdqpzaspk7plhrpoysyoklpoyzpnst97ovwgnskpensxfh8wgavouhplrj+9/b0pad4xsoix5fd7+h74udvenlru0f61tt1r6vuc2vtzvvxiop5zsvpnjb93p4nefofrpeqxpnk5dbus2zt9u++0vtuvyfelfwq1rt2u7j86ejyl5hrsz7/9+x80nt94637xdx8yu//+/d93jb+785sjvwdu/j+9nzc1fvv9p7a5v1frmdl8+nd4spru34zqklohwd0qktwhnpwdjf1ly/5ssl82ibuzjjyidl3pyfswdjwezb1mi7vazn8zwh+68l7wjdq04okszlurkrfuig7tjkgsersq1dsusqateq4o31kk9pjnrq/qmrijuvjmcrho5uyzqvkmmtioqjbqhlesjcm1x3qaaaltuleqvr4no2c2x/a2bwafrnibattyiiwmnusm46begyczdy7ctc47iztdkbjdj1u09ad9v9/qcqeskdlbrpx4pfvys9y+nzovefcbxpcb0hrlh+en9cnzg/lrn+fhieto+nuo9pmlqzkbezpyqhrrzz1zporwm4ddwuilauakhpfb5uiuzyicblsbfsodlm/kysgwv6izihta3l4kkip1670khljvqwjyvooqm2biak1j7f3lb81nbkkap6rnalzpo5vrpbp2okqq3nbowpyiz6kvqa23fkx1dmlwak2jgozovtrkpmt1k5rjguyqk5ugsi3z1h7wrxoza1xqglgflqk8zq975ip3rpn6dkda+r5esfr54vsymd4mjcjtrmmhs6tlc1pshfmpstqnta3vbmo2zloiuw5thch0lmzkqsu6+fhw46kigqhynlasxpmslubr8kd0ba77fboztvyi/oqhtoocx4ossqhlldldnympxyuei2rylhwrmnwi9orlkhpm9uipahqyzvzxojgjirhzx8wz80lspn8z30kxca3l4haj7dexym1k5vsmvg9ceoysm0vsao2yjkzrbfizjedjbxojkt1crgzojeq1cs3d1ypyt/tjddybb0dh3seo8d14qdhmnqn+bugktgb7hzzp45du0y0er2ytdseo3e+28njxcrovwdbvq8rt8pavq8st7mfrf6l9nwi5hrnewtbvh4mcbrs9r/ceuuh5aafmnpkktbjt+7ojnqtvr3e6h2d3xu7ykkgur8vgr65wacicjn/3pi8nijxzyyfsntohpxoiaw+uzhfbtjvwhkr0iyf3b8grhdiyvapcqecujn+fhd8f4awhtfbxvkjgjkboiaotxtf/vwitrlhidtfuybwrhbu8l5rqjp6zcy+tjq7iefl9bbh2slp6hftrowus6h2jvx25gkv6ehxpazsfaqybwotgit9iothtdwkrmdt/exzz6xk9e4wrh+h4/9yfplc5pxk6bsuoxjn/z0lf40e10vuziq2wbsbzfoooai99m6f6hevzx71r6dh5rfrgygsvx3wi0dvhle2rheehgw/rasf8ryjil5kvvwira/l+subezl58hw8odxh/d6afjzjpz58fqgrv2h93qb8y/gz/byqhimjhsct9fjqozqyscdxr2w/mbxv2qzfgpxpumt+brzcscn6pcf5fedwe/jrieetgwxd4mum5rt8fkbpjtfx2ejx6rmcb78jc6gqmmpg8oogtufyjuy6rn8zhk839qzb7wmfkzt4ubdb4qvlutke364e5fxgw8/goz/bzgwnv3og56iqpoy0wmsfwa8vvay1jm2d/ulp4beofb+wfmm43gxoetxcmpvvcpejkhwedbdyyp3cchzhvr1cubefmulvh0tm58hxs200m0kln2tp5cf47tphhysnpv/q4gk5kbqvwl8wjohdz5wjja7bqpixwpymhluezeb/9aksd4b+i4y7l5wtjrtao8vwu48stwo38vwb+qp+n7dwjopew/ilut/gpe0hjdzpdk/utg7e4/k9p0nt4ott6okvofwyehrc4/09gqrpv08e6f4cfjomv/2nywd+bqwx+tgzfnuxkz+o6exgdul89q/tbwj2z8v4yepr80svj5j3unplj4nxe2y/elt7xiqps/przm8r+4fq5sgdwf0o+j2yhxi4t7qj9vrcz285gfpt7xr74epr89tl2w+e0uulkun3co3ghz19uoyf3wldll/muwt5lqogvpucxx4o+r1b8ps8qx6lag+1esfurin67z/uun+igxkn5ffqg98hvw9+bp12fx7zdb+dre/lbe7o9mench5j6q9tp7rbs9t7z51d39rrb7jt+qpss1va6z/w01vllzh7s6v1o9z+ihydq8/p3n+bov5lzv7u3on9wmc7g1skzn9+b99+4i6er6z2d3f1fozx0g9glznnm+sd3b+gbbnypr3cxuigc2bs7hes2hfa90oon99c3u/j/i4hfsvzd7gvfpb3pkzfeh8zkmh1iyhsun/g1t6w39xjr8ha2k3kawdxwpn9i8/zuhxld4c0hn/v+moge4yrmyyqk703eh6r6xmcaiewzf7z0up1mso/k4gbuj4+ae+xw7m5ymri7xjcb3x6bggwhm/+aawho8og8hbm+d13fjj0ak5y00iampe7rzxewgdg9ocfesdsavgczvg9c300oh7o3gqxwgui8k02x2ycwuxs9q/8juqmvh9mejq7f5oapyps6sctpqp6fjcz53rxt8c/qmt/4mxhoabcfpfn4effotkti4fgklif1lrj5hrj096xqm122gdptlfv7qlmel5uftxzk8nrsmxdeyp5bbm+d/wz8ehq39xkkkfvoszpz/nps/x/ndwti1eg0iycmlv9vbxrzgmabuamnah05tbnuohbra4w7mowrzbfu5bamwzj55me7nswobljeqg+hdyt8vwl60xszjvti0rnjqhv2n3s09gj+bqsnoi05phryoh5pie3ngg82umadb1f7wc3dzq+wbwb9f/5alowb8hid9oewmwn85t/bswmgyi3bdsibegwrxvojetnxmzcwhyggs9g+k6t1fdytnkbmzs2uy5byklzz392mrljkh68htlaal7pd3yxuvgr/iw6ge2hh05oj5wtiypaahljiqjvu4kpnk/vsmryrppj+sl5zvsrgp5vcbcp6qic6pxsjj68rdkityf81igyhy/pjff0p2kkvzdwcdwyxzbxr6rcep0yzejthyw+iym6nxfcmqnw9jek5aqih8f1ewveap3ht9laqnx5vymfeotxixb5jeqghmv3my+al3d7d3jb4nq3bgokszduaxox7i9u+897+789ybx1n/n5m8bk0iuh2jgct9v18ug//rno8csg83qxx8tq01bxqzviosn0uuvb0u2/yhluz1vcgyfuak23u6dv8dydvxl1+696+2+ioz3+677tp5eqnbxv0ewm9gn98byoe6fm7x+bcwvibviboyc6fhv1ohr3fsshtxf1ikk+ctbnjcbcatq52bdssx11vr2mqupzrn+v1wr9fn82vq/op2rruav7s97+dnspbrxih9fhxkj4suqgpufpyfwulrysbglmollt5j7mecsbfn7mqgancx6riez4odghnztx8perdcsuj2/cdbza3yyjhmbmjr19xasc8tkgb0n/j1+oigy+bdinkffuf/bjuztbt6aal0hvzga4rfzghllwiotnoqbb9pkxj5wguerdcchi3ljiekmqwzvnjhvvmwzefpkxjzegusgcoer8fscocdqbgetk4cjmkbpuzravmsekxmus4w9/so7ksenfbhy1fltgm7n/ivzxt4hxhestvs+x6jneq5phze1rknrgejdozxyur+kzgf0g6krxz+mmpgveca6ltebxgisshtw9zhecbqee0wunkxr7hfwjvde3ypujuusxopnoo/o0/dgdlyg7aazi56vnyzyh1hla99mhi4/duoiror5o6qi/pdxx69mart3otfkkhjqd76qpq0vkssovq7s/jwdxq2uysusufuftg0udq6k4qrgymzfigoe4ngixfuepm7zxi6qhulplbmcxhpafijlk37p2wlorsiqvjv2dm/ikfsbb96uq0yvtmbmpm4jzhhsomhec7musrfyzjxt0mep6ctcox5qsqo1+gobobi6vzmkzltsma+prfot2lwvmqbwnvycbepfi2b9xb7x5g0vy9lsubbndwaa6zvmpgygwrm3g1dfgkqnforrc+jm3rtzvepkriayhnzc1i5sdsmlk/whcjdwqyatpyaaaaabjru5erkjggg=='} alt=""/> 168 \</div> 169 \<div classname="login social item"> 170 \<img classname="login social item image" src={'data\ image/png;base64,ivborw0kggoaaaansuheugaaaoeaaadhcamaaaajbsjiaaaav1bmvewzmzn///+skpkvlzwrkzh19fwgokdg4ocampqjo6p8/py+vr7l5ex29vb5+fniymirq6vq0ndp6enw1ta3t7fu1ns7u7uwsldkysrv7+/b29vi4uktra2ojcyuaaajguleqvr4no2d6zrqiaygkdsldrsrvh3v/zppq6pjjculxhlnod9/av8lauistkjsq8oxaetzfgjkclqhrboojxxoglcvae0dyz33doyitxdoubnhnrvhdysfqjoacfd7c4f39whxhfvj99cig/obryesbbpwqjjl7apfn7kl1rifmfavziebchzq2fqgdqwe9cgi/ckcctqfn/cyevh6sbqfnxapajysd4hnwacalpd4qmtc3gnjlsnqwprgjiwgqjnkgjq4hbxqrxvnrr4sk/atbpqzhjejd2ax7yfhh8hjihloyudjzb4tjzd3rwrko2k8wgu8chtlkreoteirrha+yzkhj8uibje+amwj9krihb9yh5vzdq+krijzurkhxllxclfivnhrjfwsoityijqbhzeik5rqzkl6vhrctiukogiud5nriix0flpw8gkxcffdkmdmkiieh9gntd8lhxebcdfrkvtleqixliq1il0+try5gj6rturwss+bnhdzf0pofgdnt7geavmrd+k9jiecwq5esqx3tzmthihcfwbot1gaw/avgnmtdocrer+dgyynzpye0lb0oskjfz3uzzvxphbqwpxhqzpkltxundxhbjtqgdhf9g9pihsv+4cjbkkxtilnhd5ntbj5rejs7vdaj05us9mfny+rxmrbvzu54rebc9acqhd/vssdj3jgd+3mvcq2agpjzwyg2nemr9d/qprwh89j0xwxn/xsactxwgyltpzp+53ymju1exu8pnxm04shbv4uba/befibumwzn6ewpk5kc27p29worbp5uw02sk8rbo6tsw+xy/1bwddv3j3cotpz612xu9s0x6bv+qthsxpenxqm8mvox2weijnq1rvf1wysx0mjz4vbzwd7v9prxmm2n6foadt1byu4zsywwtko/cevr2qkzaqds2jb1xz3pmyqwg2v7/jkabb1dqbdjnefr8acmyadccvwf355p24x0tcqkym986e9hsuktvjp2x/6on7u/aptc/l8381lzfpnjczxmbgp+nlt11x3gr3tdpt8n6xufboe4tp76rwgduv2qooonxpwwalrikx48fx7myftopvbpj7kiurceqdxsoljyrcgd8gxitiy6yrduov7nsyoscbsxeapqhbekqfsqaiikxcnsytehjkbgigc+rfz6dikkeny6loi93kgz5xcenanietgeahxcpsealmomggbuk0zvclbysc4yapzypwftxgoirz/okbudrtjumiyngeiu0mameiwweeb8o0fqrhsbmucvkveckeijg0i+pphqt1mxs0pfgyyem2/iiosiew4hvyirxpaitjiqpstep37ekhquwipb4oqowzdso/uhagvf0jgtgza2cj+hiycdibq8yo0zzzq+wkv7+xztfj8hirtdcv/0k+i59dfusoqmoelxopyrfthafqt7tv2uvjcjxcqtatcffof4uztj+xmfbchxu/fiqfojcsqx0qto3xir6h3rmac+gjxwjsppw3aq4gl60ytp4nwq6h3nuqc+gi1+i8c5ueme2o1ni6fhokh1lpzcqjzok6odtm9zan6cbdacxnbcoaqlwiuryelzmcjte7vawynh1drzbfsngocuovmma2oezjoqhu6taezfeoewinoaialcuk8mgukhzrxgyvckzu0corqj9x+e/4nvokvlbzfjdak0+69cmvmfl2eafno72vpxfbeagnfdk9q1zrio2c161itujx23p7gbveqymp/r/1hsonpcukgbfxcwtgdie4ilp6lqwbtm06o9nw0oatvokheoyf+dunjhhqd9vh3jowtoiw344ndtccjfqd4sxffnh2x2l7kp8j3ekqdepl7rn8pd2wov7gxpb9dpilh3pzgivr7rgry6xopodo98cdlqmrm817fpodei7/0ez5iy0bihuh7clwec1/e8qz7cdwbgl5oli9wrxfdnohxsytxt67wkxerxaudrijddxnbzj+ul/connbr4729hkrn/ehuwfeds4k+hfztwaj1eqouoih6cxxpigdzskf1e2ovgdhilfhocjg3vr00/zkbo/miqlh9g49iykebcbu73o6fxf8brtcodkfdcykybbgqdtbccywubrgqdcl4kfv6rymyg/mm3xsqlx1hgidh23ttqwk5xv/9jevtpgjcgw5himmnab+v50qdjtr7jjgitwo0tpgoa9obpcelsdyjdl/gnzynnh1cwl+prfhvv8riutxv9k/ynpxihfqz2b7klbwaeb6nrffmjqkr0/rdnwdz74u2kkhiykr38jui8eh3ttfu97l+mqy4oelootv535+qwfageygoponaqlduzu0weh1kfor6wr+mzqaqbrv/rda2mprjfjsaerzqriju/hftml6glg2mnfp5lcrakuaoura+g0okibl9is0pfuzgjfr8mih8qvjdqwq9bmi4kzvq7xyde3nyzq3scifapojlunfjiccn0lojk43ghhchycj/vrilcos6uqxchb5tsjoij4dfnqocljjaivr3trupvjhvh2ghq5+mpfu6ezumve2kxobehqgqfuoe7ih5lcj7sk165tzduzolqe4ryvd80tlvl6n5xwxcjtuz0pfdpj4knxqgiuee4hdczb9/ce5k+uugvf6kf6kl5rl4ljc6taepwldctdyjp2vvhqgijjtuynn56mgesr0pkblrfsbmpmlngy5bnikumnbdao54j6aayatniu1wrxncpj6ej3yvpxhhmltyp35nbwrkrmtp2tjnlfvnaybpeszjyxhhz+fdfnexfbb+qdrdobtcs3qecjocnhiddv0zmqfu7zmqjjyc49gthmnroe/n7dkhfeazkksjkce1ewc9s5iss3dacnbscm/7ovgix9kwaexyz3qameka4305z1tqcbnpfmb0vhbnggqik1u++nlolg1nel415tikc0va7dmrjaj7rpq7x33vpvnfvzfltu3sl8resowhhfqsgcjex1p/lu7yl1vtbeb9qd6fjo05b1k7z1nxoy5ijldvzfu2b09lvzqb1x5/alyvmmpfht+c/6dv/qmh/ovcu90claaaaabjru5erkjggg=='} alt=""/> 171 \</div> 172 \</div> 173 \<p classname="form hint">don't have an account? \<a classname="form link" href="#">sign up\</a>\</p> 174 \</div> 175 )} 176 {currentuser !== null && ( 177 \<div classname="container"> 178 \<h2 classname="heading">{'user screen'}\</h2> 179 \<divider /> 180 \<h2 classname="heading">{`hello ${currentuser get('username')}!`}\</h2> 181 \<div classname="form buttons"> 182 \<button 183 onclick={() => douserlogout()} 184 type="primary" 185 classname="form button" 186 color={'#208aec'} 187 size="large" 188 block 189 > 190 log out 191 \</button> 192 \</div> 193 \</div> 194 )} 195 \</div> 196 ); 197 };1 import react, { usestate, fc, reactelement } from 'react'; 2 import ' /app css'; 3 import { button, divider, input } from 'antd'; 4 import facebooklogin from 'react facebook login/dist/facebook login render props'; 5 const parse = require('parse/dist/parse min js'); 6	 7 export const userlogin fc<{}> = () reactelement => { 8 // state variables 9 const \[username, setusername] = usestate(''); 10 const \[password, setpassword] = usestate(''); 11 const \[currentuser, setcurrentuser] = usestate\<parse object | null>(null); 12	 13 const douserlogin = async function () promise\<boolean> { 14 // note that these values come from state variables that we've declared before 15 const usernamevalue string = username; 16 const passwordvalue string = password; 17 try { 18 const loggedinuser parse user = await parse user login(usernamevalue, passwordvalue); 19 // login returns the corresponding parseuser object 20 alert( 21 `success! user ${loggedinuser get('username')} has successfully signed in!`, 22 ); 23 // to verify that this is in fact the current user, `current` can be used 24 const currentuser parse user = await parse user current(); 25 console log(loggedinuser === currentuser); 26 // clear input fields 27 setusername(''); 28 setpassword(''); 29 // update state variable holding current user 30 getcurrentuser(); 31 return true; 32 } catch (error any) { 33 // error can be caused by wrong parameters or lack of internet connection 34 alert(`error! ${error message}`); 35 return false; 36 } 37 }; 38	 39 const douserlogout = async function () promise\<boolean> { 40 try { 41 await parse user logout(); 42 // to verify that current user is now empty, currentasync can be used 43 const currentuser parse user = await parse user current(); 44 if (currentuser === null) { 45 alert('success! no user is logged in anymore!'); 46 } 47 // update state variable holding current user 48 getcurrentuser(); 49 return true; 50 } catch (error any) { 51 alert(`error! ${error message}`); 52 return false; 53 } 54 }; 55	 56 // function that will return current user and also update current username 57 const getcurrentuser = async function () promise\<parse user | null> { 58 const currentuser (parse user | null) = await parse user current(); 59 // update state variable holding current user 60 setcurrentuser(currentuser); 61 return currentuser; 62 } 63	 64 const handlefacebookloginloginresponse = async function(response any) promise\<boolean> { 65 // check if response has an error 66 if (response error !== undefined) { 67 console log(`error ${response error}`); 68 return false; 69 } else { 70 try { 71 // gather facebook user info 72 const userid string = response id; 73 const useremail string = response email; 74 const useraccesstoken string = response accesstoken; 75 // try to login on parse using linkwith and these credentials 76 // create a new parse user object 77 const usertologin parse user = new parse user(); 78 // set username and email to match facebook profile email 79 usertologin set('username', useremail); 80 usertologin set('email', useremail); 81 try { 82 let loggedinuser parse user = await usertologin 83 linkwith('facebook', { 84 authdata {id userid, access token useraccesstoken}, 85 }); 86 // login returns the corresponding parseuser object 87 alert( 88 `success! user ${loggedinuser get('username')} has successfully signed in!`, 89 ); 90 // update state variable holding current user 91 getcurrentuser(); 92 return true; 93 } catch (error any) { 94 // error can be caused by wrong parameters or lack of internet connection 95 alert(`error! ${error message}`); 96 return false; 97 } 98 } catch (error any) { 99 console log("error gathering facebook user info, please try again!") 100 return false; 101 } 102 } 103 } 104	 105 return ( 106 \<div> 107 \<div classname="header"> 108 \<img 109 classname="header logo" 110 alt="back4app logo" 111 src={ 112 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png' 113 } 114 /> 115 \<p classname="header text bold">{'react on back4app'}\</p> 116 \<p classname="header text">{'user login'}\</p> 117 \</div> 118 {currentuser === null && ( 119 \<div classname="container"> 120 \<h2 classname="heading">{'user login'}\</h2> 121 \<divider /> 122 \<div classname="form wrapper"> 123 \<input 124 value={username} 125 onchange={(event) => setusername(event target value)} 126 placeholder="username" 127 size="large" 128 classname="form input" 129 /> 130 \<input 131 value={password} 132 onchange={(event) => setpassword(event target value)} 133 placeholder="password" 134 size="large" 135 type="password" 136 classname="form input" 137 /> 138 \</div> 139 \<div classname="form buttons"> 140 \<button 141 onclick={() => douserlogin()} 142 type="primary" 143 classname="form button" 144 color={'#208aec'} 145 size="large" 146 block 147 > 148 log in 149 \</button> 150 \</div> 151 \<divider /> 152 \<div classname="login social"> 153 \<facebooklogin 154 appid="4573670722644997" 155 fields="email" 156 callback={handlefacebookloginloginresponse} 157 render={(renderprops {onclick () => void}) => ( 158 \<div classname="login social item login social item facebook"> 159 \<img onclick={renderprops onclick} classname="login social item image" src={'https //findicons com/files/icons/2830/clean social icons/250/facebook png'} alt=""/> 160 \</div> 161 )} 162 /> 163 \<div classname="login social item"> 164 \<img classname="login social item image" src={'data\ image/png;base64,ivborw0kggoaaaansuheugaaan8aaadicamaaad5w+jtaaabwvbmvex////qqzu0qfnchft7vauufppk7f08gvr0o/zzofb7uqd7uadpncp/vqdqpzaspk7plhrpoysyoklpoyzpnst97ovwgnskpensxfh8wgavouhplrj+9/b0pad4xsoix5fd7+h74udvenlru0f61tt1r6vuc2vtzvvxiop5zsvpnjb93p4nefofrpeqxpnk5dbus2zt9u++0vtuvyfelfwq1rt2u7j86ejyl5hrsz7/9+x80nt94637xdx8yu//+/d93jb+785sjvwdu/j+9nzc1fvv9p7a5v1frmdl8+nd4spru34zqklohwd0qktwhnpwdjf1ly/5ssl82ibuzjjyidl3pyfswdjwezb1mi7vazn8zwh+68l7wjdq04okszlurkrfuig7tjkgsersq1dsusqateq4o31kk9pjnrq/qmrijuvjmcrho5uyzqvkmmtioqjbqhlesjcm1x3qaaaltuleqvr4no2c2x/a2bwafrnibattyiiwmnusm46begyczdy7ctc47iztdkbjdj1u09ad9v9/qcqeskdlbrpx4pfvys9y+nzovefcbxpcb0hrlh+en9cnzg/lrn+fhieto+nuo9pmlqzkbezpyqhrrzz1zporwm4ddwuilauakhpfb5uiuzyicblsbfsodlm/kysgwv6izihta3l4kkip1670khljvqwjyvooqm2biak1j7f3lb81nbkkap6rnalzpo5vrpbp2okqq3nbowpyiz6kvqa23fkx1dmlwak2jgozovtrkpmt1k5rjguyqk5ugsi3z1h7wrxoza1xqglgflqk8zq975ip3rpn6dkda+r5esfr54vsymd4mjcjtrmmhs6tlc1pshfmpstqnta3vbmo2zloiuw5thch0lmzkqsu6+fhw46kigqhynlasxpmslubr8kd0ba77fboztvyi/oqhtoocx4ossqhlldldnympxyuei2rylhwrmnwi9orlkhpm9uipahqyzvzxojgjirhzx8wz80lspn8z30kxca3l4haj7dexym1k5vsmvg9ceoysm0vsao2yjkzrbfizjedjbxojkt1crgzojeq1cs3d1ypyt/tjddybb0dh3seo8d14qdhmnqn+bugktgb7hzzp45du0y0er2ytdseo3e+28njxcrovwdbvq8rt8pavq8st7mfrf6l9nwi5hrnewtbvh4mcbrs9r/ceuuh5aafmnpkktbjt+7ojnqtvr3e6h2d3xu7ykkgur8vgr65wacicjn/3pi8nijxzyyfsntohpxoiaw+uzhfbtjvwhkr0iyf3b8grhdiyvapcqecujn+fhd8f4awhtfbxvkjgjkboiaotxtf/vwitrlhidtfuybwrhbu8l5rqjp6zcy+tjq7iefl9bbh2slp6hftrowus6h2jvx25gkv6ehxpazsfaqybwotgit9iothtdwkrmdt/exzz6xk9e4wrh+h4/9yfplc5pxk6bsuoxjn/z0lf40e10vuziq2wbsbzfoooai99m6f6hevzx71r6dh5rfrgygsvx3wi0dvhle2rheehgw/rasf8ryjil5kvvwira/l+subezl58hw8odxh/d6afjzjpz58fqgrv2h93qb8y/gz/byqhimjhsct9fjqozqyscdxr2w/mbxv2qzfgpxpumt+brzcscn6pcf5fedwe/jrieetgwxd4mum5rt8fkbpjtfx2ejx6rmcb78jc6gqmmpg8oogtufyjuy6rn8zhk839qzb7wmfkzt4ubdb4qvlutke364e5fxgw8/goz/bzgwnv3og56iqpoy0wmsfwa8vvay1jm2d/ulp4beofb+wfmm43gxoetxcmpvvcpejkhwedbdyyp3cchzhvr1cubefmulvh0tm58hxs200m0kln2tp5cf47tphhysnpv/q4gk5kbqvwl8wjohdz5wjja7bqpixwpymhluezeb/9aksd4b+i4y7l5wtjrtao8vwu48stwo38vwb+qp+n7dwjopew/ilut/gpe0hjdzpdk/utg7e4/k9p0nt4ott6okvofwyehrc4/09gqrpv08e6f4cfjomv/2nywd+bqwx+tgzfnuxkz+o6exgdul89q/tbwj2z8v4yepr80svj5j3unplj4nxe2y/elt7xiqps/przm8r+4fq5sgdwf0o+j2yhxi4t7qj9vrcz285gfpt7xr74epr89tl2w+e0uulkun3co3ghz19uoyf3wldll/muwt5lqogvpucxx4o+r1b8ps8qx6lag+1esfurin67z/uun+igxkn5ffqg98hvw9+bp12fx7zdb+dre/lbe7o9mench5j6q9tp7rbs9t7z51d39rrb7jt+qpss1va6z/w01vllzh7s6v1o9z+ihydq8/p3n+bov5lzv7u3on9wmc7g1skzn9+b99+4i6er6z2d3f1fozx0g9glznnm+sd3b+gbbnypr3cxuigc2bs7hes2hfa90oon99c3u/j/i4hfsvzd7gvfpb3pkzfeh8zkmh1iyhsun/g1t6w39xjr8ha2k3kawdxwpn9i8/zuhxld4c0hn/v+moge4yrmyyqk703eh6r6xmcaiewzf7z0up1mso/k4gbuj4+ae+xw7m5ymri7xjcb3x6bggwhm/+aawho8og8hbm+d13fjj0ak5y00iampe7rzxewgdg9ocfesdsavgczvg9c300oh7o3gqxwgui8k02x2ycwuxs9q/8juqmvh9mejq7f5oapyps6sctpqp6fjcz53rxt8c/qmt/4mxhoabcfpfn4effotkti4fgklif1lrj5hrj096xqm122gdptlfv7qlmel5uftxzk8nrsmxdeyp5bbm+d/wz8ehq39xkkkfvoszpz/nps/x/ndwti1eg0iycmlv9vbxrzgmabuamnah05tbnuohbra4w7mowrzbfu5bamwzj55me7nswobljeqg+hdyt8vwl60xszjvti0rnjqhv2n3s09gj+bqsnoi05phryoh5pie3ngg82umadb1f7wc3dzq+wbwb9f/5alowb8hid9oewmwn85t/bswmgyi3bdsibegwrxvojetnxmzcwhyggs9g+k6t1fdytnkbmzs2uy5byklzz392mrljkh68htlaal7pd3yxuvgr/iw6ge2hh05oj5wtiypaahljiqjvu4kpnk/vsmryrppj+sl5zvsrgp5vcbcp6qic6pxsjj68rdkityf81igyhy/pjff0p2kkvzdwcdwyxzbxr6rcep0yzejthyw+iym6nxfcmqnw9jek5aqih8f1ewveap3ht9laqnx5vymfeotxixb5jeqghmv3my+al3d7d3jb4nq3bgokszduaxox7i9u+897+789ybx1n/n5m8bk0iuh2jgct9v18ug//rno8csg83qxx8tq01bxqzviosn0uuvb0u2/yhluz1vcgyfuak23u6dv8dydvxl1+696+2+ioz3+677tp5eqnbxv0ewm9gn98byoe6fm7x+bcwvibviboyc6fhv1ohr3fsshtxf1ikk+ctbnjcbcatq52bdssx11vr2mqupzrn+v1wr9fn82vq/op2rruav7s97+dnspbrxih9fhxkj4suqgpufpyfwulrysbglmollt5j7mecsbfn7mqgancx6riez4odghnztx8perdcsuj2/cdbza3yyjhmbmjr19xasc8tkgb0n/j1+oigy+bdinkffuf/bjuztbt6aal0hvzga4rfzghllwiotnoqbb9pkxj5wguerdcchi3ljiekmqwzvnjhvvmwzefpkxjzegusgcoer8fscocdqbgetk4cjmkbpuzravmsekxmus4w9/so7ksenfbhy1fltgm7n/ivzxt4hxhestvs+x6jneq5phze1rknrgejdozxyur+kzgf0g6krxz+mmpgveca6ltebxgisshtw9zhecbqee0wunkxr7hfwjvde3ypujuusxopnoo/o0/dgdlyg7aazi56vnyzyh1hla99mhi4/duoiror5o6qi/pdxx69mart3otfkkhjqd76qpq0vkssovq7s/jwdxq2uysusufuftg0udq6k4qrgymzfigoe4ngixfuepm7zxi6qhulplbmcxhpafijlk37p2wlorsiqvjv2dm/ikfsbb96uq0yvtmbmpm4jzhhsomhec7musrfyzjxt0mep6ctcox5qsqo1+gobobi6vzmkzltsma+prfot2lwvmqbwnvycbepfi2b9xb7x5g0vy9lsubbndwaa6zvmpgygwrm3g1dfgkqnforrc+jm3rtzvepkriayhnzc1i5sdsmlk/whcjdwqyatpyaaaaabjru5erkjggg=='} alt=""/> 165 \</div> 166 \<div classname="login social item"> 167 \<img classname="login social item image" src={'data\ image/png;base64,ivborw0kggoaaaansuheugaaaoeaaadhcamaaaajbsjiaaaav1bmvewzmzn///+skpkvlzwrkzh19fwgokdg4ocampqjo6p8/py+vr7l5ex29vb5+fniymirq6vq0ndp6enw1ta3t7fu1ns7u7uwsldkysrv7+/b29vi4uktra2ojcyuaaajguleqvr4no2d6zrqiaygkdsldrsrvh3v/zppq6pjjculxhlnod9/av8lauistkjsq8oxaetzfgjkclqhrboojxxoglcvae0dyz33doyitxdoubnhnrvhdysfqjoacfd7c4f39whxhfvj99cig/obryesbbpwqjjl7apfn7kl1rifmfavziebchzq2fqgdqwe9cgi/ckcctqfn/cyevh6sbqfnxapajysd4hnwacalpd4qmtc3gnjlsnqwprgjiwgqjnkgjq4hbxqrxvnrr4sk/atbpqzhjejd2ax7yfhh8hjihloyudjzb4tjzd3rwrko2k8wgu8chtlkreoteirrha+yzkhj8uibje+amwj9krihb9yh5vzdq+krijzurkhxllxclfivnhrjfwsoityijqbhzeik5rqzkl6vhrctiukogiud5nriix0flpw8gkxcffdkmdmkiieh9gntd8lhxebcdfrkvtleqixliq1il0+try5gj6rturwss+bnhdzf0pofgdnt7geavmrd+k9jiecwq5esqx3tzmthihcfwbot1gaw/avgnmtdocrer+dgyynzpye0lb0oskjfz3uzzvxphbqwpxhqzpkltxundxhbjtqgdhf9g9pihsv+4cjbkkxtilnhd5ntbj5rejs7vdaj05us9mfny+rxmrbvzu54rebc9acqhd/vssdj3jgd+3mvcq2agpjzwyg2nemr9d/qprwh89j0xwxn/xsactxwgyltpzp+53ymju1exu8pnxm04shbv4uba/befibumwzn6ewpk5kc27p29worbp5uw02sk8rbo6tsw+xy/1bwddv3j3cotpz612xu9s0x6bv+qthsxpenxqm8mvox2weijnq1rvf1wysx0mjz4vbzwd7v9prxmm2n6foadt1byu4zsywwtko/cevr2qkzaqds2jb1xz3pmyqwg2v7/jkabb1dqbdjnefr8acmyadccvwf355p24x0tcqkym986e9hsuktvjp2x/6on7u/aptc/l8381lzfpnjczxmbgp+nlt11x3gr3tdpt8n6xufboe4tp76rwgduv2qooonxpwwalrikx48fx7myftopvbpj7kiurceqdxsoljyrcgd8gxitiy6yrduov7nsyoscbsxeapqhbekqfsqaiikxcnsytehjkbgigc+rfz6dikkeny6loi93kgz5xcenanietgeahxcpsealmomggbuk0zvclbysc4yapzypwftxgoirz/okbudrtjumiyngeiu0mameiwweeb8o0fqrhsbmucvkveckeijg0i+pphqt1mxs0pfgyyem2/iiosiew4hvyirxpaitjiqpstep37ekhquwipb4oqowzdso/uhagvf0jgtgza2cj+hiycdibq8yo0zzzq+wkv7+xztfj8hirtdcv/0k+i59dfusoqmoelxopyrfthafqt7tv2uvjcjxcqtatcffof4uztj+xmfbchxu/fiqfojcsqx0qto3xir6h3rmac+gjxwjsppw3aq4gl60ytp4nwq6h3nuqc+gi1+i8c5ueme2o1ni6fhokh1lpzcqjzok6odtm9zan6cbdacxnbcoaqlwiuryelzmcjte7vawynh1drzbfsngocuovmma2oezjoqhu6taezfeoewinoaialcuk8mgukhzrxgyvckzu0corqj9x+e/4nvokvlbzfjdak0+69cmvmfl2eafno72vpxfbeagnfdk9q1zrio2c161itujx23p7gbveqymp/r/1hsonpcukgbfxcwtgdie4ilp6lqwbtm06o9nw0oatvokheoyf+dunjhhqd9vh3jowtoiw344ndtccjfqd4sxffnh2x2l7kp8j3ekqdepl7rn8pd2wov7gxpb9dpilh3pzgivr7rgry6xopodo98cdlqmrm817fpodei7/0ez5iy0bihuh7clwec1/e8qz7cdwbgl5oli9wrxfdnohxsytxt67wkxerxaudrijddxnbzj+ul/connbr4729hkrn/ehuwfeds4k+hfztwaj1eqouoih6cxxpigdzskf1e2ovgdhilfhocjg3vr00/zkbo/miqlh9g49iykebcbu73o6fxf8brtcodkfdcykybbgqdtbccywubrgqdcl4kfv6rymyg/mm3xsqlx1hgidh23ttqwk5xv/9jevtpgjcgw5himmnab+v50qdjtr7jjgitwo0tpgoa9obpcelsdyjdl/gnzynnh1cwl+prfhvv8riutxv9k/ynpxihfqz2b7klbwaeb6nrffmjqkr0/rdnwdz74u2kkhiykr38jui8eh3ttfu97l+mqy4oelootv535+qwfageygoponaqlduzu0weh1kfor6wr+mzqaqbrv/rda2mprjfjsaerzqriju/hftml6glg2mnfp5lcrakuaoura+g0okibl9is0pfuzgjfr8mih8qvjdqwq9bmi4kzvq7xyde3nyzq3scifapojlunfjiccn0lojk43ghhchycj/vrilcos6uqxchb5tsjoij4dfnqocljjaivr3trupvjhvh2ghq5+mpfu6ezumve2kxobehqgqfuoe7ih5lcj7sk165tzduzolqe4ryvd80tlvl6n5xwxcjtuz0pfdpj4knxqgiuee4hdczb9/ce5k+uugvf6kf6kl5rl4ljc6taepwldctdyjp2vvhqgijjtuynn56mgesr0pkblrfsbmpmlngy5bnikumnbdao54j6aayatniu1wrxncpj6ej3yvpxhhmltyp35nbwrkrmtp2tjnlfvnaybpeszjyxhhz+fdfnexfbb+qdrdobtcs3qecjocnhiddv0zmqfu7zmqjjyc49gthmnroe/n7dkhfeazkksjkce1ewc9s5iss3dacnbscm/7ovgix9kwaexyz3qameka4305z1tqcbnpfmb0vhbnggqik1u++nlolg1nel415tikc0va7dmrjaj7rpq7x33vpvnfvzfltu3sl8resowhhfqsgcjex1p/lu7yl1vtbeb9qd6fjo05b1k7z1nxoy5ijldvzfu2b09lvzqb1x5/alyvmmpfht+c/6dv/qmh/ovcu90claaaaabjru5erkjggg=='} alt=""/> 168 \</div> 169 \</div> 170 \<p classname="form hint">don't have an account? \<a classname="form link" href="#">sign up\</a>\</p> 171 \</div> 172 )} 173 {currentuser !== null && ( 174 \<div classname="container"> 175 \<h2 classname="heading">{'user screen'}\</h2> 176 \<divider /> 177 \<h2 classname="heading">{`hello ${currentuser get('username')}!`}\</h2> 178 \<div classname="form buttons"> 179 \<button 180 onclick={() => douserlogout()} 181 type="primary" 182 classname="form button" 183 color={'#208aec'} 184 size="large" 185 block 186 > 187 log out 188 \</button> 189 \</div> 190 \</div> 191 )} 192 \</div> 193 ); 194 }; 이 구성 요소의 레이아웃을 완전히 렌더링하려면 app css app css 파일에 이러한 클래스를 추가하세요 app css 1 @import ' antd/dist/antd css'; 2	 3 app { 4 text align center; 5 } 6	 7 html { 8 box sizing border box; 9 outline none; 10 overflow auto; 11 } 12	 13 , 14 before, 15 after { 16 margin 0; 17 padding 0; 18 box sizing inherit; 19 } 20	 21 h1, 22 h2, 23 h3, 24 h4, 25 h5, 26 h6 { 27 margin 0; 28 font weight bold; 29 } 30	 31 p { 32 margin 0; 33 } 34	 35 body { 36 margin 0; 37 background color #fff; 38 } 39	 40 container { 41 width 100%; 42 max width 900px; 43 margin auto; 44 padding 20px 0; 45 text align left; 46 } 47	 48 header { 49 align items center; 50 padding 25px 0; 51 background color #208aec; 52 } 53	 54 header logo { 55 height 55px; 56 margin bottom 20px; 57 object fit contain; 58 } 59	 60 header text bold { 61 margin bottom 3px; 62 color rgba(255, 255, 255, 0 9); 63 font size 16px; 64 font weight bold; 65 } 66	 67 header text { 68 color rgba(255, 255, 255, 0 9); 69 font size 15px; 70 } 71	 72 heading { 73 font size 22px; 74 } 75	 76 flex { 77 display flex; 78 } 79	 80 flex between { 81 display flex; 82 justify content space between; 83 } 84	 85 flex child { 86 flex 0 0 45%; 87 } 88	 89 heading button { 90 margin left 12px; 91 } 92	 93 list item { 94 padding bottom 15px; 95 margin bottom 15px; 96 border bottom 1px solid rgba(0, 0, 0, 0 06); 97 text align left; 98 } 99	 100 list item title { 101 color rgba(0, 0, 0, 0 87); 102 font size 17px; 103 } 104	 105 list item description { 106 color rgba(0, 0, 0, 0 5); 107 font size 15px; 108 } 109	 110 form input { 111 margin bottom 20px; 112 } 113	 114 login social { 115 display flex; 116 justify content center; 117 margin bottom 30px; 118 } 119	 120 login social item { 121 width 54px; 122 height 54px; 123 border radius 54px; 124 padding 12px; 125 margin 0 12px; 126 border 1px solid #e6e6e6; 127 box shadow 0 2px 4px #d6d6d6; 128 } 129	 130 login social item facebook { 131 padding 4px; 132 background color #3c5b9b; 133 } 134	 135 login social item image { 136 width 100%; 137 } 138	 139 form hint { 140 color rgba(0, 0, 0, 0 5); 141 font size 16px; 142 text align center; 143 } 새로운 기능을 테스트해 보세요 facebook에 로그인할 수 있었고 parse linkwith linkwith 호출이 성공적이었다면, 다음과 같은 성공 메시지를 볼 수 있어야 합니다 3 사용자 로그인 확인 및 세션 생성 facebook 로그인이 작동했는지 확인하려면, parse 대시보드를 확인하고 새로운 사용자 사용자 (당신의 facebook 인증 데이터가 다른 사용자에 속하지 않는 경우)와 함께 facebook authdata authdata 매개변수를 확인할 수 있습니다 대시보드에서 유효한 세션이 생성되었음을 확인할 수 있으며, 해당 사용자 사용자 객체에 대한 포인터가 포함되어 있습니다 4 기존 사용자를 facebook 로그인에 연결하기 또 다른 linkwith linkwith 가능한 사용법은 기존 사용자를 다른 인증 제공자, 이 경우에는 facebook과 연결하는 것입니다 다음 기능을 추가하여 linkwith linkwith 를 호출합니다 이는 userlogin userlogin 구성 요소에 로그인하는 것과 동일한 방식입니다 여기서 유일한 차이점은 빈 parse user parse user ,에서 메서드를 호출하는 대신 현재 로그인된 사용자 객체에서 사용한다는 것입니다 javascript 1 const handlefacebookloginlinkresponse = async function(response) { 2 // check if response has an error 3 if (response error !== undefined) { 4 console log(`error ${response error}`); 5 return false; 6 } else { 7 try { 8 // gather facebook user info 9 const userid = response id; 10 const useraccesstoken = response accesstoken; 11 // try to link current parse user using linkwith and these credentials 12 // get current user 13 const usertolink = await parse user current(); 14 try { 15 let loggedinuser = await usertolink 16 linkwith('facebook', { 17 authdata {id userid, access token useraccesstoken}, 18 }); 19 // login returns the corresponding parseuser object 20 alert( 21 `success! user ${loggedinuser get( 22 'username', 23 )} has successfully linked his facebook account!`, 24 ); 25 // update state variable holding current user 26 getcurrentuser(); 27 return true; 28 } catch (error) { 29 // error can be caused by wrong parameters or lack of internet connection 30 alert(`error! ${error message}`); 31 return false; 32 } 33 } catch (error) { 34 console log("error gathering facebook user info, please try again!") 35 return false; 36 } 37 } 38 }1 const handlefacebookloginlinkresponse = async function(response any) promise\<boolean> { 2 // check if response has an error 3 if (response error !== undefined) { 4 console log(`error ${response error}`); 5 return false; 6 } else { 7 try { 8 // gather facebook user info 9 const userid string = response id; 10 const useraccesstoken string = response accesstoken; 11 // try to link current parse user using linkwith and these credentials 12 // get current user 13 const usertolink parse user = await parse user current(); 14 try { 15 let loggedinuser parse user = await usertolink 16 linkwith('facebook', { 17 authdata {id userid, access token useraccesstoken}, 18 }); 19 // login returns the corresponding parseuser object 20 alert( 21 `success! user ${loggedinuser get( 22 'username', 23 )} has successfully linked his facebook account!`, 24 ); 25 // update state variable holding current user 26 getcurrentuser(); 27 return true; 28 } catch (error any) { 29 // error can be caused by wrong parameters or lack of internet connection 30 alert(`error! ${error message}`); 31 return false; 32 } 33 } catch (error any) { 34 console log("error gathering facebook user info, please try again!") 35 return false; 36 } 37 } 38 } 이 기능을 홈 화면의 다른 react facebook login react facebook login 구성 요소에 할당하세요 이 구성 요소는 앱에 현재 사용자가 로그인했을 때만 표시됩니다 새로운 기능을 테스트하고, parse user parse user 객체 authdata authdata 값이 새로운 인증 제공자 데이터로 업데이트될 것임을 주의하세요 사용자가 실제로 parse 서버 대시보드에서 업데이트되었는지 확인하세요 결론 이 가이드의 끝에서, facebook 로그인을 사용하여 react에서 parse 사용자에게 로그인, 가입 또는 기존 사용자를 연결하는 방법을 배웠습니다 다음 가이드에서는 apple 로그인 사용 방법을 보여드리겠습니다