112017.10
17:50:30

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的意义何在呢?难道仅仅是绑定一些事件之类的?

已有0条回复 回复
102017.10
11:04:51

在js里面方便的遍历一个对象(含数组),数组遍历是有forEach,但是它没有break操作,它会一定遍历完整个数组。我自己写个foreach函数,可以遍历数组和对象:

function foreach(obj, callback) {
  if (typeof obj !== 'object') {
    return
  }

  if (Array.isArray(obj)) {
    for (let i = 0, len = obj.length; i < len; i ++) {
      let value = obj[i]
      let state = callback(i, value, obj)
      if (state === false) {
        break
      }
    }
  }
  else {
    let keys = Object.keys(obj)
    for (let i = 0, len = keys.length; i < len; i ++) {
      let key = keys[i]
      let value = obj[key]
      let state = callback(key, value, obj)
      if (state === false) {
        break
      }
    }
  }
}

使用的时候:

foreach(obj, (key, value) => {
  ...
  return false
})

callback中返回false,就表示break,返回true,表示continue,不返回任何值表示正常遍历。

已有0条回复 回复
062017.10
17:14:07

通过对基金公司数据的抓取,通过自己开发的软件简单分析了一下,出了下面这张图,简单显示了基金公司成立时间、规模、基金支数、评级(天相评级)关系:

基金公司成立时间、规模、基金支数、评级(天相评级)关系图

y轴是这家公司的总管理资产,天弘基金一枝独秀,比第二的公司多出一个位,达到15187.62亿元,真的是三十年河东三十年河西,连摩根士丹利(中国)都比不上。圆的颜色代表天相评级,越靠近红色,评级越高,灰色的是0评级。圆的大小代表该基金公司拥有的基金支数,可以看出来基金支数很多的公司大部分集中在一个小区域内,即2000-2005年前后成立的,总资产在2000-4000亿上下的区间。但是,基金支数最多的公司,评级都不怎么特别高。

我们选择基金,往往需要看它的母公司的投资能力,评级虽然不精确,但大体可以看出平均水平。像天虹基金这样的公司,总资产很大,基金支数少,说明整个公司专注的领域比较少,专注度就更高,但是这样的公司,如果遇到金融危机,很有可能就一锅端了,死的粉身碎骨。投资者在选择基金的时候,看看这些数据也是很好玩的。

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

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.

已有0条回复 回复
272017.9
23:19:52

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

前景与背景配色方案

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

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

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

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

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

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.

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

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

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

已有0条回复 回复
062017.9
11:14:07

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

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

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

已有0条回复 回复
062017.9
10:13:23

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

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

已有0条回复 回复