Blockstack.js 工具教程css
在本教程中,咱们将使用Gaia存储系统构建一个区块链微博应用程序,从而使用户提交的文字和图片没有发布到中心服务器中,而是在本身的本地电脑。
此应用程序将是一个彻底分散且无需服务器的access . js应用程序。标识和存储服务将由blockstack提供,html
应用程序将可以执行如下操做:react
咱们将使用如下工具:webpack
对于经验丰富的blockstack开发人员:git
安装与生成github
首先,安装Yeoman以及blockstack应用程序生成器:web
npm install -g yo generator-blockstack
接下来,为咱们的应用程序建立一个目录,取个新的名字Publik :npm
mkdir publik && cd publik
而后,使用blockstack应用程序生成器生成一个简单的blockstack应用程序:json
yo blockstack:react
响应提示后,应用程序生成器将建立全部应用程序文件,而后安装全部依赖项。浏览器
要在本地运行应用程序:
npm start
并将浏览器打开到http://localhost : 8080。如今您应该看到一个简单的react应用程序,您可使用blockstack ID登陆。
多用户层数据存储
在多用户层数据存储中,存储在Gaia上的用户文件经过用户配置文件中的apps属性对其余用户可见。使用多用户层数据存储的每一个应用程序都必须将其自身添加到用户的配置文件. JSON文件中。在身份验证期间请求publish _ data做用域时,blockstack浏览器将自动处理此部分。
所以,咱们须要作的第一件事是修改身份验证请求以包括publish _ data范围。
打开src/components/App.jsx并找到下面的方法:
handleSignIn(e) { e.preventDefault(); redirectToSignIn(); }
将方法修改成:
handleSignIn(e) { e.preventDefault(); const origin = window.location.origin redirectToSignIn(origin, origin + '/manifest.json', ['store_write', 'publish_data']) }
请注意,默认状况下,身份验证请求包括启用存储的store _ write范围。
若是您想注销并再次登陆,程序将为提示用户身份验证的请求,你将会容许该程序发布你本地所存储的文字或图片。
发布状态:
在此步骤中,咱们将添加容许发布和显示“状态”的功能。
让咱们打开src / components / profile . jsx,而后从blockstack. js中导入咱们将使用的几个方法。这些方法是putFile ( )、getFile ( )和lookupProfile ( )。将它们添加到文件顶部附近blockstack的import语句中:
import { isSignInPending, loadUserData, Person, getFile, putFile, lookupProfile } from 'blockstack';
而后,咱们须要在构造函数( )的初始状态中添加一些属性。构造函数应以下所示:
constructor(props) { super(props); this.state = { person: { name() { return 'Anonymous'; }, avatarUrl() { return avatarFallbackImage; }, }, username: "", newStatus: "", statuses: [], statusIndex: 0, isLoading: false }; }
如今,让咱们修改render ( )方法以添加文本输入和提交按钮,以即可以发布用户的“微博状态”。将render ( )方法替换为如下内容:
render() { const { handleSignOut } = this.props; const { person } = this.state; const { username } = this.state; return ( !isSignInPending() && person ? <div className="container"> <div className="row"> <div className="col-md-offset-3 col-md-6"> <div className="col-md-12"> <div className="avatar-section"> <img src={ person.avatarUrl() ? person.avatarUrl() : avatarFallbackImage } className="img-rounded avatar" id="avatar-image" /> <div className="username"> <h1> <span id="heading-name">{ person.name() ? person.name() : 'Nameless Person' }</span> </h1> <span>{username}</span> <span> | <a onClick={ handleSignOut.bind(this) }>(Logout)</a> </span> </div> </div> </div> <div className="new-status"> <div className="col-md-12"> <textarea className="input-status" value={this.state.newStatus} onChange={e => this.handleNewStatusChange(e)} placeholder="What's on your mind?" /> </div> <div className="col-md-12"> <button className="btn btn-primary btn-lg" onClick={e => this.handleNewStatusSubmit(e)} > Submit </button> </div> </div> </div> </div> </div> : null ); }
在上面的render ( )方法中,咱们还显示了用户的blockstack ID。咱们须要从用户配置文件数据中提取这一点。找到componentWillMount ( )方法,并在person属性下面添加用户名属性:
componentWillMount() { this.setState({ person: new Person(loadUserData().profile), username: loadUserData().username }); }
接下来,咱们将添加两种方法来处理输入事件:
handleNewStatusChange(event) { this.setState({newStatus: event.target.value}) } handleNewStatusSubmit(event) { this.saveNewStatus(this.state.newStatus) this.setState({ newStatus: "" }) }
而后执行所需存储操做,下面是保存一个“微博状态”的方法:
saveNewStatus(statusText) { let statuses = this.state.statuses let status = { id: this.state.statusIndex++, text: statusText.trim(), created_at: Date.now() } statuses.unshift(status) const options = { encrypt: false } putFile('statuses.json', JSON.stringify(statuses), options) .then(() => { this.setState({ statuses: statuses }) }) }
如今,您应该能够在文本框中键入一个状态,而后按“提交”按钮将其保存。
当您按下submit (提交)按钮时,您将看到什么也不会发生。由于咱们没有添加任何代码来显示状态。
显示状态
返回render ( )方法,并在包含文本输入和提交按钮的div元素正下方添加如下块。
<div className="col-md-12 statuses"> {this.state.isLoading && <span>Loading...</span>} {this.state.statuses.map((status) => ( <div className="status" key={status.id}> {status.text} </div> ) )} </div>
咱们还须要在页面加载时获取状态,因此咱们添加一个名为fetchData ( )的新方法,并从componentDidMount ( )方法调用它
componentDidMount() { this.fetchData() } fetchData() { this.setState({ isLoading: true }) const options = { decrypt: false } getFile('statuses.json', options) .then((file) => { var statuses = JSON.parse(file || '[]') this.setState({ person: new Person(loadUserData().profile), username: loadUserData().username, statusIndex: statuses.length, statuses: statuses, }) }) .finally(() => { this.setState({ isLoading: false }) }) }
此时,咱们有一个基本的“区块链微博”应用程序,能够用来发布和查看本身的状态。可是,没法查看其余用户的状态。在接下来的步骤中,咱们将进入“多用户数据存储”部分。可是首先,让咱们花点时间来完善咱们的应用程序。
打开src/styles/style.css,并用如下内容替换现有样式:
/* Globals */ a,a:focus,a:hover{color:#fff;} html,body{height:100%;text-align:center;background-color:#191b22;} body{color:#fff} .hide{display:none;} .landing-heading{font-family:'Lato',Sans-Serif;font-weight:400;} /* Buttons */ .btn{font-family:'Lato',Sans-Serif;padding:0.5625rem 2.5rem;font-size:0.8125rem;font-weight:400;line-height:1.75rem;border-radius:0!important;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;} .btn-lg{font-size:1.5rem;padding:0.6875rem 3.4375rem;line-height:2.5rem;} .btn:focus,.btn:active:focus,.btn.active:focus{outline:none;} .btn-primary{color:#fff;border:1px solid #2C96FF;background-color:#2C96FF;} .btn-primary:hover,.btn-primary:focus,.btn-primary:active{color:#fff;border:1px solid #1a6ec0;background-color:#1a6ec0;} /* Avatar */ .avatar{width:100px;height:100px;} .avatar-section{margin-bottom:25px;display:flex;text-align:left;} .username{margin-left:20px;} /* Scaffolding */ .site-wrapper{display:table;width:100%;height:100vh;min-height:100%;} .site-wrapper-inner{display:flex;flex-direction:column;justify-content:center;margin-right:auto;margin-left:auto;width:100%;height:100vh;} .panel-authed{padding:0 0 0 0;} /* Home button */ .btn-home-hello{position:absolute;font-family:'Source Code Pro',monospace;font-size:11px;font-weight:400;color:rgba(255,255,255,0.85);top:15px;left:15px;padding:3px 20px;background-color:rgba(255,255,255,0.15);border-radius:6px;-webkit-box-shadow:0px 0px 20px 0px rgba(0,0,0,0.15);-moz-box-shadow:0px 0px 20px 0px rgba(0,0,0,0.15);box-shadow:0px 0px 20px 0px rgba(0,0,0,0.15);} /* Input */ input, textarea{color:#000;padding:10px;} .input-status{width:100%;height:70px;border-radius:6px;} .new-status{text-align:right;} /* Statuses */ .statuses{padding-top:30px;} .status{margin:15px 0px;padding:20px;background-color:#2e2e2e;border-radius:6px}
若是一切顺利,咱们最终的结果应该是这样的:
用户配置文件查找
如今让咱们修改 Profile.jsx以显示其余用户的配置文件。咱们将使用blockstack . js提供的lookupProfile ( )方法,咱们在前面的导入语句中添加了该方法。lookupProfile ( )接受单个参数,该参数是要查找的配置文件的blockstack ID,并返回配置文件对象。
首先,咱们将对应用程序的路由结构进行一些更改,以便经过访问http:// localhost:8080/other_user.id来查看其余用户的配置文件
安装 react-router:
npm install --save react-router-dom
打开src/index.js并添加到文件顶部:
import { BrowserRouter } from 'react-router-dom'
接下来,将src / index . js中的reactdom . render ( )方法更改成:
ReactDOM.render(( <BrowserRouter> <App /> </BrowserRouter> ), document.getElementById('root'));
Then we'll need to go back to src/components/App.jsx and add the new route. Open src/components/App.jsx and import the Switch and Route components from react-router-dom:
import { Switch, Route } from 'react-router-dom'
接下来,在render ( )方法中找到下面的行:
: <Profile handleSignOut={ this.handleSignOut } />
并将其替换为:
: <Switch> <Route path='/:username?' render={ routeProps => <Profile handleSignOut={ this.handleSignOut } {...routeProps} /> } /> </Switch>
这会设置路由并捕获要用做配置文件查找用户名的路由参数。
咱们还须要在webpack配置中添加一个规则,以便正确处理包含的URL路径。角色。例如: http://localhost:8080/other_user.id 注意:在生产应用程序中,须要配置web服务器来处理此问题。
在根项目目录中打开webpack . config . js,而后找到如下行:
historyApiFallback: { disableDotRule: true },
更改成:
historyApiFallback: { disableDotRule: true },
**注:咱们须要再次运行启动NPM,这样才能生效。
如今,咱们跳回到src / components / profile . jsx,并添加一个方法来肯定是查看本地用户的配置文件仍是其余用户的配置文件。**
isLocal() { return this.props.match.params.username ? false : true }
而后咱们能够修改fetchData ( )方法,以下所示:
fetchData() { this.setState({ isLoading: true }) if (this.isLocal()) { const options = { decrypt: false } getFile('statuses.json', options) .then((file) => { var statuses = JSON.parse(file || '[]') this.setState({ person: new Person(loadUserData().profile), username: loadUserData().username, statusIndex: statuses.length, statuses: statuses, }) }) .finally(() => { this.setState({ isLoading: false }) }) } else { const username = this.props.match.params.username lookupProfile(username) .then((profile) => { this.setState({ person: new Person(profile), username: username }) }) .catch((error) => { console.log('could not resolve profile') }) } }
咱们首先使用isLocal ( )检查是否正在查看本地用户配置文件或其余用户的配置文件。若是是本地用户配置文件,咱们将运行前面添加的getFile ( )函数。不然,咱们使用lookupProfile ( )方法查找属于用户名的配置文件。
注意:对于https部署,用于名称查找的默认块堆栈核心API端点应更改成指向经过https提供的核心API。不然,因为浏览器阻止混合内容,名称查找将失败。有关详细信息,请参阅blockstack . js文档。
为了获取用户的状态,咱们在调用lookupProfile (用户名)后当即向fetchData ( )添加如下lookupProfile(username)... catch((error)=>{..}块:
const options = { username: username, decrypt: false } getFile('statuses.json', options) .then((file) => { var statuses = JSON.parse(file || '[]') this.setState({ statusIndex: statuses.length, statuses: statuses }) }) .catch((error) => { console.log('could not fetch statuses') }) .finally(() => { this.setState({ isLoading: false }) })
最后,咱们须要有条件地呈现注销按钮、状态输入文本框和提交按钮,以便它们在查看其余用户的配置文件时不会显示。在render ( )方法中,经过使用{ isLocal ( ) & &...}条件:
{this.isLocal() && <span> | <a onClick={ handleSignOut.bind(this) }>(Logout)</a> </span> } //... {this.isLocal() && <div className="new-status"> <div className="col-md-12"> <textarea className="input-status" value={this.state.newStatus} onChange={this.handleNewStatusChange} placeholder="What's on your mind?" /> </div> <div className="col-md-12 text-right"> <button className="btn btn-primary btn-lg" onClick={this.handleNewStatusSubmit} > Submit </button> </div> </div> }
ok!将浏览器指向http://localhost:8080/your_blockstack.id以查看配置文件。注意:您须要有一个注册的blockstack ID才能使此操做生效。
要查看本教程的完整源代码,请访问:https://github.com/larrysalib...
欢迎加入blockstack中国开发者群q(官方blockstack core开发者在内):加微信:six四九四叁壹六seven一