构建React的想法 - from sebmarkbage

  1. 1. 转换 - Transformation
  2. 2. 抽象 - Abstraction
  3. 3. 组合 - Composition
  4. 4. 状态 - State
  5. 5. 记忆方法
  6. 6. 列表
  7. 7. 持续性
  8. 8. 状态Map
  9. Reference

从github翻到的论述,是React设计者试图说明其构建React的整个逻辑。

1. 转换 - Transformation

React的核心假定是UI层实际上是对数据的展现形式的一种转换。同样的输入会给出同样的输出结果,只是表现形式可能会有所区别。

function NameBox(name) {
  return { fontWeight: 'bold', labelContent: name };
}

'Sebastian Markbåge' ->
{ fontWeight: 'bold', labelContent: 'Sebastian Markbåge' };

2. 抽象 - Abstraction

我们无法将一个复杂的UI放到一个方法当中的。将UI抽象到各个可以复用的组件当中就变得尤为重要。抽象成可复用的组件,并且隐藏实现的细节,是我们想要做的。

function FancyUserBox(user) {
  return {
    borderStyle: '1px solid blue',
    childContent: [
      'Name: ',
      NameBox(user.firstName + ' ' + user.lastName)
    ]
  };
}

{ firstName: 'Sebastian', lastName: 'Markbåge' } ->
{
  borderStyle: '1px solid blue',
  childContent: [
    'Name: ',
    { fontWeight: 'bold', labelContent: 'Sebastian Markbåge' }
  ]
};

3. 组合 - Composition

为了实现真正可以复用的特性,仅仅使用细分的子功能,并且每次给他们构建容器是不太够的。我们需要能够建立中间层的抽象,即将几个子功能组件组合起来,形成另一层次的组件。这里的组合就是指将多个抽象融合成一个抽象的能力。

function FancyBox(children) {
  return {
    borderStyle: '1px solid blue',
    children: children
  };
}

function UserBox(user) {
  return FancyBox([
    'Name: ',
    NameBox(user.firstName + ' ' + user.lastName)
  ]);
}

4. 状态 - State

UI不仅仅是服务器以及商业逻辑的复制,实际上是有很多状态,是服务于特定的运行过程的。比如你在一个文本框输入内容,那么我们需要一些方式能够记录下这个文本框当前的状态,并且用这个状态去和后端进或者其他的方法进行交互。

我们希望我们的数据是immutable的

function FancyNameBox(user, likes, onClick) {
  return FancyBox([
    'Name: ', NameBox(user.firstName + ' ' + user.lastName),
    'Likes: ', LikeBox(likes),
    LikeButton(onClick)
  ]);
}

// Implementation Details

var likes = 0;
function addOneMoreLike() {
  likes++;
  rerender();
}

// Init

FancyNameBox(
  { firstName: 'Sebastian', lastName: 'Markbåge' },
  likes,
  addOneMoreLike
);

5. 记忆方法

如果我们知道这是个纯方法,并且还会重复的call它,那么我们可以设计一个记忆版本的方法,这样我们就不用在有相同的数据(输入)的时候还要重复执行了

function memoize(fn) {
  var cachedArg;
  var cachedResult;
  return function(arg) {
    if (cachedArg === arg) {
      return cachedResult;
    }
    cachedArg = arg;
    cachedResult = fn(arg);
    return cachedResult;
  };
}

var MemoizedNameBox = memoize(NameBox);

function NameAndAgeBox(user, currentTime) {
  return FancyBox([
    'Name: ',
    MemoizedNameBox(user.firstName + ' ' + user.lastName),
    'Age in milliseconds: ',
    currentTime - user.dateOfBirth
  ]);
}

// 我们同样可以不仅仅记一个值,也可以记一个map
function memoize(fn) {
  return function(arg, memoizationCache) {
    if (memoizationCache.arg === arg) {
      return memoizationCache.result;
    }
    const result = fn(arg);
    memoizationCache.arg = arg;
    memoizationCache.result = result;
    return result;
  };
}

function FancyBoxWithState(
  children,
  stateMap,
  updateState,
  memoizationCache
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState,
      memoizationCache.get(child.key)
    ))
  );
}

const MemoizedFancyNameBox = memoize(FancyNameBox);

6. 列表

大部分的UI都是一些形式的列表,然后为在列表中的每个元素产出不同的一系列的值。这就自然的产生了一个有层级的结构。

我们可以通过使用Map方法来管理每个列表当中的元素的状态。

function UserList(users, likesPerUser, updateUserLikes) {
  return users.map(user => FancyNameBox(
    user,
    likesPerUser.get(user.id),
    () => updateUserLikes(user.id, likesPerUser.get(user.id) + 1)
  ));
}

var likesPerUser = new Map();
function updateUserLikes(id, likeCount) {
  likesPerUser.set(id, likeCount);
  rerender();
}

UserList(data.users, likesPerUser, updateUserLikes);

7. 持续性

一些时候,我们在运行我们的核心商业逻辑的时候会大量的操作数据,这部分关于数据的操作会显得有些冗余,我们可以将其移出核心逻辑的代码块,比如使用bind,来绑定方法,在其他地方写具体的代码逻辑。

function FancyUserList(users) {
  return FancyBox(
    UserList.bind(null, users)
  );
}

const box = FancyUserList(data.users);
const resolvedChildren = box.children(likesPerUser, updateUserLikes);
const resolvedBox = {
  ...box,
  children: resolvedChildren
};

8. 状态Map

我们可以用组合来将几个子组件放在一起来使用,同样的,对于他们需要的一些输入数据,我们可以通过state,来传到下层的方法处,供他们使用。

function FancyBoxWithState(
  children,
  stateMap,
  updateState
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState
    ))
  );
}

function UserList(users) {
  return users.map(user => {
    continuation: FancyNameBox.bind(null, user),
    key: user.id
  });
}

function FancyUserList(users) {
  return FancyBoxWithState.bind(null,
    UserList(users)
  );
}

const continuation = FancyUserList(data.users);
continuation(likesPerUser, updateUserLikes);

Reference

https://github.com/reactjs/react-basic


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 stone2paul@gmail.com

文章标题:构建React的想法 - from sebmarkbage

文章字数:1.1k

本文作者:Leilei Chen

发布时间:2020-04-09, 11:25:08

最后更新:2020-04-09, 11:31:08

原始链接:https://www.llchen60.com/%E6%9E%84%E5%BB%BAReact%E7%9A%84%E6%83%B3%E6%B3%95-from-sebmarkbage/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏