Hoodie&Reactを使用したオフライン優先アプリ。 パート2:承認

私たちの目標は、オフライン優先のアプリケーション、つまりインターネット接続がなくてもすべての機能をロードして保持するSPAを作成することです。 ストーリーの最初の部分では 、ブラウザーデータベースの使用方法を学びました。 今日は、サーバーデータベースとの同期を構成し、承認を有効にします。 その結果、オフラインでもさまざまなデバイスでデータを編集し、接続が表示されたときに同期することができます。







Couchdb



はい、サーバー上でこの特定のデータベースが必要です。 Pouchdb-Serverは現在活発に開発されており、 LevelDBに基づいたCouchDB APIを模倣しています。 Hoodieはデフォルトでそれで動作します。これは初心者向けのインストールを簡素化するために行われます。 しかし、開発目的であってもチーズです。 たぶん運がよかったのかもしれませんが、初めてフーディーを取得しようとして3日間を費やし、奇妙なエラー、3日間の問題、プルリクエストにぶつかったのです。 そして、失望の寸前で、私は通常のCouchDBをインストールすることに決め、私の問題はすべて終わりました。 したがって、オープンソースに実行可能な貢献をしたいのでなければ、すぐに後者を置くことをお勧めします。







ほとんどのディストリビューションでは、CouchDBは標準ツールを使用してインストールされます。







debianも使用する場合

ここに私が使用した命令があります 。 ただし、/ /etc/init.d/coucdb



/ /etc/init.d/coucdb



/ /etc/init.d/coucdb



を削除して、supervisordの監視下に置くまで、データベースは常に落ちていました。最後の構成は次のとおりです。







 [program:couchdb] user=couchdb environment=HOME=/usr/local/var/lib/couchdb command=/usr/local/bin/couchdb autorestart=true stdout_logfile=NONE stderr_logfile=NONE
      
      





ベースを設定したら、管理者を作成します。







 curl -X PUT $HOST/_config/admins/username -d '"password"'
      
      





そして、CORSをオンにします。







 npm install -g add-cors-to-couchdb add-cors-to-couchdb -u username -p password
      
      





package.json



サーバーを起動するコマンドをわずかに修正するだけです。







 "server": "hoodie --port 8000 --dbUrl 'http://username:password@127.0.0.1:5984'"
      
      





すべてがうまくいったことを願っています:)







ログイン



AppBarには、コンテキストメニュー付きの承認アイコンがあります。 したがって、別のコンポーネントにApp.js



し、 App.js



代わりにAppBar



で使用します。







 import NavBar from './NavBar' <NavBar account={hoodie.account} />
      
      





そこで、認証用のAPIを提供するhoodie.account



を渡します。









そして、サブスクライブできるイベント:









そして、ここにコンポーネント自体があります:







Navbar.js
 import React from 'react' import AppBar from 'material-ui/AppBar' import FlatButton from 'material-ui/FlatButton' import IconButton from 'material-ui/IconButton' import IconMenu from 'material-ui/IconMenu' import MenuItem from 'material-ui/MenuItem' import KeyIcon from 'material-ui/svg-icons/communication/vpn-key' import AccountIcon from 'material-ui/svg-icons/action/account-circle' import AuthDialog from './AuthDialog' export default class NavBar extends React.Component { constructor(props) { super(props) this.state = { isSignedIn: this.props.account.isSignedIn(), openedDialog: null } } signOutCallback = () => this.setState({isSignedIn: false}) signInCallback = () => this.setState({isSignedIn: true}) componentDidMount() { this.props.account.on('signout', this.signOutCallback) this.props.account.on('signin', this.signInCallback) } componentWillUnmount() { this.props.account.off('signout', this.signOutCallback) this.props.account.off('signin', this.signInCallback) } render () { let authMenu; if (this.state.isSignedIn) { authMenu = ( <IconMenu iconButtonElement={<IconButton><AccountIcon /></IconButton>} targetOrigin={{horizontal: 'right', vertical: 'top'}} anchorOrigin={{horizontal: 'right', vertical: 'top'}} > <MenuItem primaryText="Sign Out" onTouchTap={() => this.props.account.signOut()} /> </IconMenu> ) } else { authMenu = ( <IconMenu iconButtonElement={<IconButton><KeyIcon /></IconButton>} targetOrigin={{horizontal: 'right', vertical: 'top'}} anchorOrigin={{horizontal: 'right', vertical: 'top'}} > <MenuItem primaryText="Sign Up" onTouchTap={() => this.setState({openedDialog: 'signup'})} /> <MenuItem primaryText="Sign In" onTouchTap={() => this.setState({openedDialog: 'signin'})} /> </IconMenu> ) } return ( <div> <AppBar title="Action Loop" showMenuIconButton={false} iconElementRight={authMenu} /> <AuthDialog account={this.props.account} action={this.state.openedDialog} handleClose={() => this.setState({openedDialog: null})} /> </div> ) } }
      
      





state



には、アイコンとメニューをレンダリングするための現在の承認状態があります。 そして、現在開いているダイアログ(登録、エントリ、またはnull



すべてが閉じている場合)。 componentDidMount



エントリイベントと終了イベントをサブスクライブします。 render



、許可状態に応じて目的のアイコンrender



表示します。 承認ダイアログを描画するために残ります:







AuthDialog.js
 import React from 'react'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; import TextField from 'material-ui/TextField'; export default class AuthDialog extends React.Component { constructor(props) { super(props); this.state = { username: '', password: '', }; } handleConfirm = () => { const account = this.props.account; const username = this.state.username.trim(); const password = this.state.password.trim(); if (!username || !password) { return; } if (this.props.action == 'signup') { account.signUp({username, password}) .then(() => { return account.signIn({username, password}) }) .catch(console.error) } else { account.signIn({username, password}) .catch(console.error) } this.props.handleClose(); this.clearState(); } handleCancel = () => { this.props.handleClose(); this.clearState(); } handleSubmit = (e) => { e.preventDefault(); this.handleConfirm(); } clearState = () => { this.setState({ username: '', password: '' }) } render () { const buttons = [ <FlatButton label="Cancel" primary={true} onTouchTap={this.handleCancel} />, <FlatButton label="Submit" type="submit" primary={true} keyboardFocused={true} onTouchTap={this.handleConfirm} /> ]; return ( <div> <Dialog title={this.props.action == 'signup' ? 'Sign Up' : 'Sign In'} actions={buttons} modal={false} open={this.props.action !== null} onRequestClose={this.handleCancel} contentStyle={{maxWidth: 400}} > <form onSubmit={this.handleSubmit}> <TextField name="username" floatingLabelText="Username" onChange={(e) => this.setState({username: e.target.value})} /> <TextField name="password" floatingLabelText="Password" onChange={(e) => this.setState({password: e.target.value})} /> </form> </Dialog> </div> ); } }
      
      





登録ダイアログとログインダイアログには同じフォームフィールドがあるため、これらを1つに結合します。 コンポーネントのロジックは基本的ですhandleConfirm



または最初のレジスタを入力してから入力します。







許可中にループ自体を再ロードします。 App.js



イベントへの反応を追加します。







  componentDidMount() { hoodie.store.on('change', this.loadLoops); hoodie.account.on('signin', this.loadLoops) hoodie.account.on('signout', this.loadLoops) } componentWillUnmount() { hoodie.store.off('change', this.loadLoops); hoodie.account.off('signin', this.loadLoops) hoodie.account.off('signout', this.loadLoops) }
      
      





終わり



これで、承認の準備ができました。 この部分の最大の課題は、おそらくCouchDBのインストールでした。 これで、アプリケーションは接続が切断されても機能を保持し、表示されると同期されます。 ただし、サイトを完全に閉じると、インターネットなしでは開くことができません。 これは次の最後の部分で修正します。







»このパートのコードは、 https//github.com/imbolc/action-loopタグpart2から入手できます。








All Articles