Closed Aliveing closed 4 years ago
CC @Chen-jj
欢迎提交 Issue~
如果你提交的是 bug 报告,请务必遵循 Issue 模板的规范,尽量用简洁的语言描述你的问题,最好能提供一个稳定简单的复现。🙏🙏🙏
如果你的信息提供过于模糊或不足,或者已经其他 issue 已经存在相关内容,你的 issue 有可能会被关闭。
Good luck and happy coding~
暂时的解决办法:在A的 componentDidMount 事件中用setTimeout来设置state。
A组件
componentDidMount() { setTimeout(() => this.setState({value: 1}), 0); }
@Aliveing CLI 和依赖版本保持一致
@Chen-jj 统一使用1.3.34
版本,issue中的问题依然存在。
taro info(更新为CLI与依赖一致)
@Aliveing Page 和 Component 的 componentDidMount 分别对应小程序的 onReady 和 ready。
如果 A 是页面、B 是组件,componentWillReceiveProps 的 nextProps 是会有可能等于 this.props。这是因为页面的 onReady 触发时间有可能在所有页面 ready 前或所有页面 ready 后,onReady 最先触发的情况下就会有问题,这里你只能换种写法。
但如果 A 和 B 都是组件,B ready 肯定比 A 早,因此 componentWillReceiveProps 的 nextProps 没有错。
至于 componentWillReceiveProps 会触发两次,复现不了。
Hello~
您的问题楼上已经有了确切的回答,如果没有更多的问题这个 issue 将在 15 天后被自动关闭。
如果您在这 15 天中更新更多信息自动关闭的流程会自动取消,如有其他问题也可以发起新的 Issue。
Good luck and happy coding~
@Chen-jj 我把复现代码更新了一下,让console更详细一些,这个问题核心就在于 B 的 componentWillReceiveProps触发了两次并且这两次nextProps和this.props都相同,并且不是概率性的,而这两次的原因只有两个来源,一个是B didMount的时候更新state,一个是A didMount时更新state导致B的props改变。 为了方便查看以下是运行的结果:
1. --------------class B render undefined // (B.props.value)
2. --------------class B did mount undefined // (B.props.value & B setState didMount=true)
3. --------------class A didMount undefined // (A.state.value & A setState value=1)
4. --------------class B render 1 // (B.props.value)
5. --------------class B receive props 1 1 true // (nextProps.value B.props.value B.state.didMount)
6. --------------class B render 1 // (B.props.value)
7. --------------class B receive props 1 1 true // (nextProps.value B.props.value B.state.didMount)
8. --------------class B render 1 // (B.props.value)
9. --------------class A didMount & after setState 1 // (A.state.value)
10. --------------class B didMount & after setState true // (B.state.didMount)
问题就是:
@Chen-jj 今天在开发的时候发现 componentWillReceiveProps 生命周期的触发条件真的非常迷,而且传来的数据也是迷到不行,当props改变时有概率不触发,导致写的组件在某些概率下不能根据传来的数据加载值,浪费了整整两天时间。
如果taro在这个生命周期上有问题,应该写在文档里告诉开发尽量不去使用,或者什么情况下才能避免这种情况的发生,而在官方开发文档的 组件生命周期 中只字未提,我个人其实不在意taro因为各平台的原因而导致某些写法不能支持,只不过taro说是可以用react编写不同平台,但是这种常用生命周期的差异性为何不提?为何不在开发文档中提前告知开发者,而是让开发者自己在开发时发现问题,并在github上以为是bug提交后再被贴一个 question
的标签,希望taro能将这种差异性补充到各端开发前注意。
终于还是放弃了这个生命周期,用shouldComponentUpdate + componentDidUpdate 来模拟,虽然写的麻烦点,但是没有所谓概率性触发问题。
@Aliveing 还是维持我上述回答,componentWillReceiveProps 并没复现调用多次。你没说 A 是页面还是组件,如果 A 是页面,那不要这样写,小程序 Page 的 onReady 触发时机不稳定。但如果 A 是组件,那完全没有问题。
均没有复现 componentWillReceiveProps 调用多次。
@Chen-jj 好的,我依次说明下:
以下是我运行的console截图:
@Aliveing 额,setState 怎会触发 componentWillReceiveProps。这里只应触发一次。
A 是页面,componentDidMount 由 onReady 触发,微信小程序页面 onReady 触发时机不稳定。这时你不要强依赖 componentDidMount 的顺序做逻辑便是。
@Chen-jj 抱歉是我记错了,去查了查 react 文档,和getDerivedStateFromProps生命周期记混了,不过触发两次componentWillReceiveProps通过复现代码在我这边是100%的概率,我再重新建一个新项目试试。
以下是我当前工程中的package.json文件
package.json 截图
@Chen-jj 首先感谢一直跟踪回复,我试了试,新建的项目确实没问题,挨个排查以后,十分惊奇的是,taro-listview
这个组件会导致两次触发componentWillReceiveProps,只要新建的项目安上了这个组件,即使工程中没有引用taro-listview也会发生这个触发两次的bug。
原因目前不详,猜测是taro-listview的package.json引用了老版本的taro,编译的时候导致taro版本被覆盖了,如果是这样的话,taro有没有什么方法可以获取到当前编译使用的taro版本是什么?
还有就是有个疑问,一个三方组件,为什么可以影响到taro整体的生命周期?
重新fork了一下 taro-listview
,把其中 package.json 做了以下改动
这样安装完 taro-listview 后 node_modules/taro-listview/node_modules 里就没有老旧版本的taro了,两次触发componentWillReceiveProps的问题也就好了。 但是我还是依然想知道taro在编译三方组件的时候如果版本不统一,为何会出现这种奇怪的问题? @Chen-jj
嗯... 我理解npm的依赖处理机制,不过经过测试有意思的来了,如果只在 taro-listview
环境下(taro@1.3.15)就不会出现触发两次的情况,只有在这两个版本(taro@1.3.15 & taro@1.3.34)同时存在时,才会触发两次,可能之前我没表达清楚,重新描述一下问题:
为什么在工程中我引用了一个 taro 的三方组件,而这个组件使用了与当前工程不同的 taro 版本,经过 npm run dev:weapp 编译后会导致工程内组件的生命周期 componentWillReceiveProps 触发两次?
一定程度上是 CLI 的 AST 分析问题。
所以现阶段只能先这样,然后等待 taro-cli AST能正确转译?
这... 关闭了?CLI 的 AST 分析问题已经解决了?
问题描述
A组件嵌套了B组件,A组件中把state值当作props传给B,并在A的componentDidMount中设置 A新的state,并在B的componentDidMount中设置自己新的state,B组件的componentWillReceiveProps会触发两次,并且两次nextProps和当前props值相同,作为组件类普遍都在 componentWillReceiveProps事件中比较props值,来运行组件功能代码或者保存新的实例变量数据,这个bug就导致比较props值相同,这种触发机制用着挺难受。
复现步骤
talk is cheap show you the code
A 组件
B组件
期望行为
被嵌套的组件能正确触发componentWillReceiveProps生命周期
报错信息
系统信息
补充信息
生命周期触发问题,没有等到A组件真正渲染完毕就触发componentDidMount