282017.10

slickgrid中getItem, getItemById, getItemByIdx和row, id, index

在原始数据中,使用index的概念:
1> 使用getItemByIdx(index)来获取某个数据
2> 通过getIdexById(id)来获取它在原始数据中的index

在当前的视图中(有的情况下和原始数据不同,比如排序、筛选、tree收缩状态下),使用row的概念:
1> 使用getItem(row)来获取某个数据
2> 通过getRowById(id)来获取它在当前视图中的row

使用id就可以干任何事情:
1> 使用getItemById(id)来获取某个数据
2> 通过getRowById(id)来获取它在当前视图中的row
3> 通过getIdexById(id)来获取它在原始数据中的index

比如想通过当前视图中某行数据的row来获取它在原始数据中的index,就必须通过getItem(row)->item.id->getIdxById(id)这样的方法来获取。

21:01:00 已有1条回复
  1. 感谢
    #837 会飞的小蜗牛 2019-08-25 20:53 回复
272017.10

flex盒子模型的grow部分子元素宽高不能用百分比

在使用flex盒子模型一段时间之后,发现这货的坑真是不少,其中最最让人难理解的,就是它的flex-grow部分的子元素无法使用100%的对应尺寸。下面来举个例子:

<div style="display: flex; width: 300px; height: 200px;">
  <div style="width: 100px;"></div>
  <div style="flex-grow: 1">
  <div style="width: 100%; height: 100%; overflow: auto;"></div>
  </div>
</div>

上面的代码,我们希望创建一个盒子,盒子左边有一个固定100px宽度的div,右边说一个填满剩余空间的弹性伸缩div。而在这个弹性伸缩的div内部,我们希望放一个塞满整个区域的容器,容器设置了overflow: auto,因此,当这个容器内的内容超出可视区域时,会出现滚动条。

然而,事情没有想像的那么容易,上面的width: 100%并不会按我们想象的方式,使用它的父元素的宽度,而是会使用300px。

这是因为,再css标准里面,width/height如果是百分比的话,必须为它的parent提供一个确定的width/height,当然,parent的width/height也可以从再上一层继承。而如果上面这个条件不成立的话,parent会继续向上冒泡,直到找到一个确定的对应宽高为止。

不幸的是,flex的flex-grow是不确定的,因此,这里的width: 100%不能按我们想象的方式展现。

如何解决这个问题呢?那就是再在flex-grow元素的内部使用flex布局,它自己是弹性伸缩的,而你可以使它的内部元素也是弹性伸缩的:

<div style="display: flex; width: 300px; height: 200px;">
  <div style="width: 100px;"></div>
  <div style="flex-grow: 1; display: flex;">
  <div style="flex-grow: 1; height: 100%; overflow: auto;"></div>
  </div>
</div>

这样修改之后,就可以达到我们的目的。

通过这个问题的分析,基本就掌握了flex里面的精髓。“弹性”代表着没有固定宽度,而想要占满弹性容器,就必须在该容器本身实现一个新的弹性盒子模型。

19:10:13 已有0条回复
112017.10

react异步处理多次渲染的解决方案

react的组件有一个非常烦的操作,就是异步数据渲染。页面第一次打开的时候,会去mount所有的组件,但是,这个时候往往都是没有数据的,特别是通过数据驱动的SPA。大部分的方案都是在componentDidMount中请求数据,得到数据后调用this.setState更新数据。这个方案对于单个组件是没有问题的,但是,当数据来源不同,有一部分来自父组件,有一部分来自自身,就比较麻烦。有这么一个场景,父组件请求完数据之后,调用自己的setState,导致子组件界面重新渲染了,子组件此时请求数据后也setState,导致自己的界面重新渲染,这时没有父组件任何事。但是麻烦的事情接着来了,子组件自己请求数据重新渲染之后,父组件再次请求数据,虽然父组件并没有修改子组件的props,但还是导致子组件重新渲染,这时,子组件上一次请求的数据导致的渲染结果会被清空,整个子组件全部重绘了。实际上,我们希望保持子组件自己更新后的状态,并和父组件传来的props有一个merge的过程。

这种情况的大部分解决方案,是禁止子组件自己请求数据,请求数据由父组件全权代理,通过父组件的setState更新子组件的props,在子组件的componentWillReceiveProps中去更新子组件的state来达到更新子组件的视图的目的。

但是,如果我不打算采用这个方案,那么该怎么办?

还是有办法的,关键在于子组件的componentWillReceiveProps和shouldComponentUpdate。

第一个想法是只通过shouldComponentUpdate进行控制:

shouldComponentUpdate(nextProps, nextState) {
  return !isEqual(nextProps, this.props) || !isEqual(nextState, this.state);
}

isEqual是lodash的方法。这样可以判断,当新的state和新的props有任何一个有变动时,才会更新界面。然而,这需要开发者非常注意:

1.绝对不能直接操作state,举个例子:

let { items } = this.state
items.push(1)
this.setState({ items })

这个操作非常危险,看上去setState的操作是合法的,虽然你修改了state,但是你用新的是值去setState,然而,如果你这样操作,shouldComponentUpdate中的nextState将会是被push了新值的state,判断会错误。正确的做法是:

let { items } = this.state
items = items.concat(1)
this.setState({ items })

一定要用一个copy,而非直接修改state。

2.不能在componentWillReceiveProps中setState,在我的前面一篇文章里面说过,componentWillReceiveProps内部的setState是同步的,会马上更新state而不触发重绘,所以,如果你在componentWillReceiveProps中setState,那么shouldComponentUpdate中的nextState会是经过componentWillReceiveProps修改过的。

第1个问题是可以避免的,在万不得已的情况下,我们甚至可以动用lodash.cloneDeep,但是第2个问题,我们需要谨慎处理,因为我们不可能不在componentWillReceiveProps中调用setState,这时不可能的,我们异步数据处理方案只能这样去做。那么怎么解决这个问题呢?

那就是,在componentWillReceiveProps中做进一步判断,是否要更新setState,大部分情况下,如果父组件虽然重绘,但是传给子组件的props不变的话,这个子组件不需要重绘,所以,在componentWillReceiveProps中也加入一个判断:

componentWillReceiveProps(nextProps) {
  if (isEqual(this.props, nextProps)) {
    return
  }

  // ...

  this.setState({ ... })
}

shouldComponentUpdate(nextProps, nextState) {
  return !isEqual(nextProps, this.props) || !isEqual(nextState, this.state);
}

这样的处理就极为巧妙了。当父组件传给子组件的props发生变化时,子组件整个重置,用新的props重绘(之前的setState造成的改动被重置),而如果父组件传的props不变时,就不进行任何动作。

这个问题,带来了react组件的另外一个思考,如果我们的大部分组件都是依赖异步数据的,那么组件的生命周期是不是存在问题?componentDidMount的意义何在呢?难道仅仅是绑定一些事件之类的?

17:50:30 已有3条回复
  1. 哈喽,看到你这篇文章写得蛮清楚的,我遇到了一个类似的问题,想请教一下~
    当我在来回快速切换菜单的时候,每个菜单didmount的时候都分别请求各自的数据,我在上一个请求没有完成时,就手动点了下一个菜单,这时先先展现了菜单B,而后菜单A的响应完成后,又重新渲染了菜单A的view,导致我真正想要看的菜单B的view没有被渲染,请问你对这个问题有了解嘛~
    (PS: 446875622 这是我的微信号,方便的话可以加我一下,我仔细请教,麻烦了~)
    #673 一个装睡的人 2018-12-11 20:16 回复
  2. deferer-queue了解一下 https://www.tangshuang.net/6092.html
    #674 回复给#673 否子戈 2018-12-11 20:28 回复
  3. 好的,蟹蟹~
    #675 回复给#674 一个装睡的人 2018-12-11 20:30 回复
302017.9

why react component bind this in constructor

In many react component's constructor, developers always bind its methods with this, like:

export default class MyComponent extends Component {
  constructor() {
    this.say = this.say.bind(this)
  }
  ...
}

This sentence seems to be stupid. Is this regulated by react?

No!

In fact, react component class follow ES6 class std. The reason to put this sentence is because when you use this.say in your render, you alway use it as onClick callback function, this is why this is not point to instance of this component. Let's look into this code:

<a href="" onclick="alert(this.href)">click</a>

You know what this point to here, so when you use a component method as a event callback function, this in the function does not referer to the instance of component. So another way to solve this problem is to bind this when you use the method, like:

export default class MyComponent extends Component {
  constructor() {
    // do not use bind sentence
  }
  render() {
    return <a onClick={this.say.bind(this)}>click</a>
  }
}

Now you can use this in say as want you want.

01:34:09 已有0条回复
272017.9

网上看到这个前景色和背景色配色方案。放在这里备用。

前景与背景配色方案

非得写一行字,有意思么。。。

23:19:52 已有0条回复

当我从sublime转到atom时,以为遇到了真爱,但是卡卡的atom简直不忍直视,总感觉这货随时会挂掉,进王者峡谷智能是脆皮坦克一般的存在。当我抱着试一试VS CODE的心态,下载安装了之后,瞬间那种喜悦感,恨不得把自己电脑上最大的数据库文件打开来试试。VS CODE比atom更精美,速度更快,不带有疯狂的package社区,专注写代码。特别是底部打开时候的紫色工具条,太艳了。很快,我就从一个厌恶微软产品的人,转而喜爱上这款微软发布的开源编辑器。在我几乎所有的电脑上卸载掉以前的编辑器,专门用VS CODE编程。

不足之处就是快捷键和sublime不一样,要习惯很久,而且有些很实用的快捷键也不一样,导致经常按错。没办法,要舒服的躺进一个坑,就要痛苦的从前面的坑里爬出来。

21:00:06 已有0条回复
222017.9

run Photoshop CS2 on Windows10

When I downloaded the free old version of Adobe Photoshop CS2 and installed it on windows10, I found it is not able to launch the software, it comes out with a error alert, and force me to close the program. I was aware of it is a compatibility problem, but not know how to fix it. After tried a lot, I found the most easy way: using windows application tools.

  1. close your photoshop cs2 alert first
  2. open your photoshop cs2 installed directory, and select Photoshop.exe
  3. on the top of the screen, there will be a tab named Manage
  4. click Troubleshoot compatibility item
  5. follow what it call you to do, try more
  6. done

And you may need to run photoshop as administrator, for this, right click on Photoshop.exe and open properties, change to Compatibility to select Run this program as an administrator.

14:18:10 已有0条回复
122017.9

在最开始接触一个依赖的时候,把关于^~等符号的版本管理弄清楚的时候,觉得这个好伟大,然而当躺进坑里,才发现,这东西是害人的。对一个第三方package的依赖,默认安装会在版本前面加^,当第二次执行npm install的时候,如果发现npm服务器上存在比该版本大的小版本号,就会使用新的版本的package。然而,然而!当新的版本对当前环境不兼容时,特别是那些被依赖的很深的package发生这种情况,对于开发者而言,简直就是噩梦。昨天做build的时候一切还正常,连代码都没改动,今天再做build的时候,却怎么也通不过了。造成这个问题的原因,是因为所有的package的版本都向后兼容,虽然你的项目代码没有变,但是你的第三方依赖代码变了,如果新的第三方代码不兼容你当前的node版本,那么就是一个惨字。解决的唯一办法,是通过升级npm版本,升级之后,package都是扁平化的,然后再在package.json文件中,把那个不兼容的package固定在较低的版本中。

我个人的观点是,一个项目,之所以能够正常运行,是因为在开发时选择了适合的版本,而且是经过测试的。倘若在第二次运行时,代码不同,那么怎么保证之前的测试是有效的呢?因此,npm install不应该自作主张的从服务器选择更新的版本,而是在本地安装允许的最新版本。比如jquery,安装本地所有package中允许的最新版本,而不是比本地允许的版本还要新的版本。

09:21:05 已有0条回复
062017.9

在一个软件中,使用多个语言进行混合编程,不同的服务用最好的语言去执行得到结果,例如node和Python混合,php和c++。那么怎么实现呢?其实语言之间的混合编程原理很简单,以一个语言为入口程序,另一个语言为后台程序,在入口程序中如何调用后台程序的执行结果呢?那就要用到入口程序的execute能力,通过调用命令行工具,执行后台程序,并且有非常便捷的方式得到后台程序的执行结果。

这里有一篇如何实现node和python混合的文章,简单的说,就是利用node child_process能力,通过exec执行一个命令行命令,这个命令行命令调用python程序执行,并且把执行结果输出在child_process的stdout中,node在对stdout的输出结果进行解析即可。

说到这里,你就发现多语言混合编程也并不困难了。

11:14:07 已有0条回复

量化分析数据资源

https://github.com/thuquant/awesome-quant

发现一个超级棒的量化分析资源收集页面