Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React-in-patterns 笔记 #61

Closed
yuxino opened this issue May 9, 2018 · 0 comments
Closed

React-in-patterns 笔记 #61

yuxino opened this issue May 9, 2018 · 0 comments
Labels

Comments

@yuxino
Copy link
Owner

yuxino commented May 9, 2018

React-in-patterns 我个人很喜欢这本。作者还是蛮风趣幽默的。同样English不是native language,人家可以写书,我只能看他的书 ¯(ツ)/¯

Also notice that English is not my native language. If you see a typo or something sounds weird please contribute here github.com/krasimir/react-in-patterns. If you are reading from a printed version of this book then feel free to use a pen ¯(ツ)/¯

书的知识点围绕着React的各种Pattern,不会很枯燥,倒不如说很有趣。虽然都非常主观,围绕做作者的视角。以下笔记不全出自React-in-patterns,而是在看了React-in-paterns之后想到的。更多的是我自己额外的一些研究和拓展。

Event handlers

我们在看官方文档的时候应该都有见过官方说过我们可以需要通过bind(this)来绑定事件,如果我们想访问component的this。比如一个Button组件。

它可能是这么写的

class Button extends React.Component {
   constructor (props) {
     super(props);
     this.state = { message: 'React in patterns' };
   }
  
  handlerClick () {
     console.log(this.state.message)
  }   

   render () {
     return (
       <button onClick={ this.handlerClick.bind(this) }>clike me</buton>
    )
  }
}

并且它也可能是这样的

class Button extends React.Component {
   constructor (props) {
     super(props)
     this.state = { message: 'React in patterns' }
     this.handlerClick = this.handlerClick.bind(this)
   }
  
  handlerClick () {
     console.log(this.state.message)
  }   

   render () {
     return (
       <button onClick={ this.handlerClick }>clike me</buton>
    )
  }
}

它们两个谁比较好,其实很显然当然是后者,因为在列表渲染多次重绘的时候,前者会不停的调用bind函数。后者不会只会做一次。

除了上面的情况以外。在构造器里面写bind能让我们使用一个方法处理多种输入。

class Form extends React.Component {
  constructor(props) {
    super(props);
    this._onNameChanged = this._onFieldChange.bind(this, 'name');
    this._onPasswordChanged = this._onFieldChange.bind(this, 'password');
  }
  render() {
    return (
      <form>
      <input onChange={ this._onNameChanged } />
      <input onChange={ this._onPasswordChanged }
      />
      </form>
    );
  }
  _onFieldChange(field, event) {
    console.log(`${ field } changed to ${ event.target.value }`);
  }
};

HOC

HOC的确很强大社区里也很流行。我个人对这个是有偏见的,我认为它不是最佳的实现。举个我不喜欢的原因,在React的devtools里面,高度组合过的HOC组件嵌套层级真的很深到了惨不忍睹的境界。

社区里最常用的HOC库应该是recompose。之前也写过一篇关于recompose的笔记。感兴趣的可以看一下。最基本的HOC的例子如下:

var enhanceComponent = (Component) =>
  class Enhance extends React.Component {
    render() {
      return (
        <Component {...this.props} style={{ border: '1px solid red' }} />
      )
    }
  };

var OriginalTitle = () => <h1>Hello world</h1>;
var EnhancedTitle = enhanceComponent(OriginalTitle);

class App extends React.Component {
  render() {
    return <EnhancedTitle />;
  }
};

这个例子展示的是给OriginTitle组件加一层外边框。

Function as a children, render prop

这一个之前很想写的一篇也没有写闲置了。在写那篇之前这里先整理一下吧。Function as children这个我认为是React里很强大的一个概念。Function as children或者是render prop都只是写法上的不同,本质上做的还是一件事情。

function TodoList({ todos, render }) {
  return (
    <section className='main-section'>
      <ul className='todo-list'>{
        todos.map((todo, i) => (
          <li key={ i }>{ render(todo) }</li>
        ))
      }</ul>
    </section>
  );
}

return (
  <TodoList
    todos={ todos }
    render={
      todo => isCompleted(todo) ?
        <b>{ todo.label }</b> : todo.label
    } />
);

另一个版本

function TodoList({ todos, render }) {
  return (
    <section className='main-section'>
      <ul className='todo-list'>{
        todos.map((todo, i) => (
          <li key={ i }>{ children(todo) }</li>
        ))
      }</ul>
    </section>
  );
}

return (
  <TodoList
    todos={ todos }>
    {
      todo => isCompleted(todo) ?
        <b>{ todo.label }</b> : todo.label
    }
 </TodoList>
);

他们其实都是一样的在做一样的事情。TodoList 完全不知道 label 和 status 属性。行为完全由父组件自定义。

我们可以抽出行为做出更为高级的抽象。React-Media就是一个很好的例子。

import React from "react";
import Media from "react-media";

class App extends React.Component {
  render() {
    return (
      <div>
        <Media query="(max-width: 599px)">
          {matches =>
            matches ? (
              <p>The document is less than 600px wide.</p>
            ) : (
              <p>The document is at least 600px wide.</p>
            )
          }
        </Media>
      </div>
    );
  }
}

还有其他的例子比如说一个权限验证的组件。如果用户具有读取产品列表的权限,那么我们便渲染 ProductList 。

<Authorize
  permissionsInclude={[ 'read:products' ]}
  render={ () => <ProductsList /> } />

Flux

Fulx并非react特有。首先我们来看官网

Flux is the application architecture that Facebook uses for building client-side web applications. It complements React's composable view components by utilizing a unidirectional data flow. It's more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.

Flux是FaceBook用来构建客户端应用的架构。Flux通过使用单向数据流来补充React的可组合视图组件。它更多的是一种模式,而不是一个正式的框架,您可以立即开始使用Flux,而无需大量的新代码。

视频很有意思。 讲演的人是Jing Chen。中国人。这一张视频截图说明了传统MVC架构存在的问题。但是评论区也有表示FB提供的MVC的图是错误的,并且戏称Jing的做法完全不对,FB又一次发明了MVC,只是把他叫做了MVC。如果你对撕逼感兴趣转战评论区和reddit,还蛮有意思的。

image

好了言归正传。这个图的确有些问题的本人也是承认的。

Yeah, that was a tricky slide [the one with multiple models and views and bidirectional data flow], partly because there's not a lot of consensus for what MVC is exactly - lots of people have different ideas about what it is. What we're really arguing against is bi-directional data flow, where one change can loop back and have cascading effects.

但是是不妨碍我们理解。就照着Jing的话来说吧。那么上面的传统MVC架构关系非常复杂,MV双向的箭头意味着Model会改变View,同时View也会改变Model,这样在应用变得越来越复杂,特性越来越多的时候我们会非常难以追踪应用的变化状态。

这里需要补充一个例子。我个人认为我上面写的很不专业这一部分会搁置,直到找到足够多的资料。

ok 最近找到了资料其实MVC这种设计模式一直都是有很多变种,并且一直都不是很纯粹,时间证明了MVC 并不是web开发的最好实践。

一个更好的实践是MVVM。

参考资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant