HOW - WordPress.com ·...

Post on 03-Jun-2020

3 views 0 download

Transcript of HOW - WordPress.com ·...

J A C K T O L D U S “ W H Y ”S I N G L E - PA G E A P P S

H O W

N I K O L A Y B A C H I Y S K I , A U T O M A T T I C , W O R D C A M P V I E N N A , A P R I L 1 1 , 2 0 1 5

A U T O M A T T I CE X T R A P O L A T E . M E@ N I K O L A Y B

F A S T E R

M O R E E N G A G I N G

C H A N G EL E T ' S TA L K A B O U T

S T A T EL E T ' S TA L K A B O U T

O L D - S C H O O L V S .

S I N G L E - P A G E A P P S

O L D S C H O O L

C H A N G E ⇒ R E F R E S H

O L D - S C H O O L

C H A N G E ⇒

S I N G L E - P A G E

U I L I B R A R Y

N O T A F R A M E W O R K

var  Post  =  React.createClass(  {      function  render()  {          return  (              <div  className="post">                  <p  className="content">                      {  this.props.post.content  }                  </p>                  <PostMeta  post={  this.props.post  }  />              </div>          );      }  }  );  

var  Post  =  React.createClass(  {      function  render()  {          return  (              <div  className="post">                  <p  className="content">                      {  this.props.post.content  }                  </p>                  <PostMeta  post={  this.props.post  }  />              </div>          );      }  }  );   J S X

var  Post  =  React.createClass(  {      function  render()  {          return  (              React.DOM.div(                  {className:  'post'},                  [  React.DOM.p(                          null,                          this.props.post.content                      ),                      PostMeta(  {post:  this.props.post}  )              );        );      }  }  );  

var  Post  =  React.createClass(  {      function  render()  {          return  (              <div  className="post">                  <p  className="content">                      {  this.props.post.content  }                  </p>                  <PostMeta  post={  this.props.post  }  />              </div>          );      }  }  );

var  PostMeta  =  React.createClass(  {      function  getInitialState()  {          return  {  hidden:  true  };      },      function  onToggle()  {          this.setState(  {  hidden:  !  this.state.hidden  }  );      },      function  render()  {          return  (              <div  className="meta">                  {  this.props.post.author  }                  <button  onClick={  this.onToggle  }>                      {  this.state.hidden  ?  'More'  :  'Hide'  }                  </button>                  (  this.state.hidden  ?                          <p>…extra  meta…</p>  :                          null                  )              </div>          );      }  }  );

var  PostMeta  =  React.createClass(  {      function  getInitialState()  {          return  {  hidden:  true  };      },      function  onToggle()  {          this.setState(  {  hidden:  !  this.state.hidden  }  );      },      function  render()  {          return  (              <div  className="meta">                  {  this.props.post.author  }                  <button  onClick={  this.onToggle  }>                      {  this.state.hidden  ?  'More'  :  'Hide'  }                  </button>                  (  this.state.hidden  ?                          <p>…extra  meta…</p>  :                          null                  )              </div>          );      }  }  );

var  PostMeta  =  React.createClass(  {      function  getInitialState()  {          return  {  hidden:  true  };      },      function  onToggle()  {          this.setState(  {  hidden:  !  this.state.hidden  }  );      },      function  render()  {          return  (              <div  className="meta">                  {  this.props.post.author  }                  <button  onClick={  this.onToggle  }>                      {  this.state.hidden  ?  'More'  :  'Hide'  }                  </button>                  (  this.state.hidden  ?                          <p>…extra  meta…</p>  :                          null                  )              </div>          );      }  }  );

var  PostMeta  =  React.createClass(  {      function  getInitialState()  {          return  {  hidden:  true  };      },      function  onToggle()  {          this.setState(  {  hidden:  !  this.state.hidden  }  );      },      function  render()  {          return  (              <div  className="meta">                  {  this.props.post.author  }                  <button  onClick={  this.onToggle  }>                      {  this.state.hidden  ?  'More'  :  'Hide'  }                  </button>                  (  this.state.hidden  ?                          <p>…extra  meta…</p>  :                          null                  )              </div>          );      }  }  );

R E - R E N D E R S

C O M P O N E N T SL E T ' S TA L K A B I T M O R E A B O U T

C O M P O S A B L E

<MasterBar>      <UserGreeting  user="…">          <Avatar  login={  this.props.user.login  }  />          Howdy,  {  this.props.user.nickname  }          <LogOutLink  id={  this.props.user.id  }  />      </UserGreeting>  </MasterBar>

B U I L D I N G B L O C K S O F O U R A P P L I C A T I O N

<MasterBar  />  <MastHead  />  <Navigation  active="archive"  />  <Posts  date="2015-­‐04-­‐01"  author="crumb">      <Post>          …      </Post>      <Post>          …      </Post>      …  </Posts>

<MasterBar  />  <MastHead  />  <Posts  date="2015-­‐04-­‐01"  author="crumb">      <Post  post="…">          <p  class="content">              {  this.props.post.content}          </p>          <PostMeta  post="…"  />      </Post>      <Post>      …      </Post>      …  </Posts>

T E S T A B L E

P R E V E N T S X S S

<p>{  this.props.content  }</p>

<img  src="javascript:alert('XSS');">

&lt;img  src=&quot;javascript:alert(&#39;XSS&#39;);&quot;&gt;

<p  dangerouslySetInnerHTML={{  __html:  this.props.content  }}  />

N O T T E M P L A T E S

<div  class="posts">      {{#each  posts}}          <div  class="post">              {{#if  author}}          </div>      {{/each}}  </div>

R E U S A B L E

<Comment>      <Avatar  email={  this.props.comment.author.email}  />      …  </Comment>

<PostMeta>      <Avatar  email={  this.props.comment.author.email}  />      …  </PostMeta>

W A I T !

K E E P L O G I C A N D M A R K U P…A P O P U L A R B E S T P R A C T I C E S A Y S …

… S E P A R A T E !

S E P A R A T I O N O F C O N C E R N S I S G O O D , R I G H T ?

W H E N D O W E N E E D A N E V E N T H A N D L E R W I T H O U T T H E D O M E L E M E N T I T I S B O U N D T O ?

onClick()

<button>

W H E N D O W E N E E D A D O M E L E M E N T W I T H O U T T H E E V E N T H A N D L E R S F O R I T S A C T I O N S ?

onClick()

<button>

H T M L

D I S P L A Y L O G I C

T H E S A M E C O N C E R N

H T M LJ S

T H E S A M E C O N C E R N

R E - R E N D E R I N G

V I R T U A L D O M

0 . R U N render()

O N E V E R Y U P D A T E

1 . D I F F W I T H P R E V I O U S T R E E

O N E V E R Y U P D A T E

http://calendar.perfplanet.com/2013/diff/

2 . C O M P U T E M I N I M U M S E T O F D O M C H A N G E S

O N E V E R Y U P D A T E

3 . B A T C H - E X E C U T E A L L D O M U P D A T E S

O N E V E R Y U P D A T E

V I R T U A L D O M : N O T O N L Y S P E E D !

S E R V E R - S I D E R E N D E R I N G

S V G , V M L , C A N V A S

R U N N I N G I N A W E B W O R K E R

F L U Xhttps://facebook.github.io/flux/

http://blog.andrewray.me/flux-for-stupid-people/

https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture

N O T A F R A M E W O R K

A R C H I T E C T U R E B L U E P R I N T

L E T ' S C H A T

S U M M A R Y

C O M P O N E N T S , N O T T E M P L A T E S

R E - R E N D E R , D O N ' T T O U C H

T H E D O M

V I R T U A L D O M I S S I M P L E , F A S T , F U N

L E T ' S TA L K A B O U T

Q U E S T I O N S ? @ N I K O L A Y B