需求
最近在做React Native项目中需要用到Picker选择器,考虑到时间成本以及项目本身样式的统一性,(实际上样式问题已经远远排在了功能需求之后),于是自己设计了一个Picker组件。Picker功能就是:点击显示弹窗,弹窗中间显示选择列表,点击列表项和取消按钮关闭弹窗同时选中项传递到父组件
组件设计
- props就简单设计了
visiable
(显示控制)style
(样式)、value
(默认选中项)、data
(数据源),由于数据源是key:value形式,但是可能会有多种格式的key:value,就把key和value的字段也当成props传进来myKey
(自定义数据源key)、name
(自定义数据源value)
Tip:有个小问题,key 不能作为 props 传递,在组件中获取不到。
问题
其实无非就是一个弹窗的设计而已,但是问题也是出现在弹窗的关闭上。按照经验,组件可以由组件内部和组件外部关闭。 visiable
从props转为当前组件的state,然后操作本地的state就能实现功能。 刚开始是用getDerivedStateFromProps来做的,利用 nextProps.visiable!== prevState.visiable
返回 {visiable:nextProps.visiable}
实现组件更新,问题来了,组件并没有更新。分别打印getDerivedStateFromProps
的两个参数(nextProps, prevState)的时候,发现操作本地state后,getDerivedStateFromProps
这个函数会执行,由于props还是之前的props就导致上一次的props覆盖掉了刚修改的state。 而componentWillReceiveProps
只有一个nextprops参数,操作本地state就能改变组件状态了。但是既然官方更新了就使用最新的吧。 于是就多设计了一个props:hidden
方法去更改父组件的 visiable
来控制弹窗的显示与否
反思
其实想一下应该是没毛病的,react主张的就是单项数据流,保证组件数据源要单一,这样才能保证组件受控,组件显示与否要不就组件内部完成,要不就由组件外部控制,多个数据源好像确实不符合react的设计?
他们反复强调的也是一个组件的数据来源要保持唯一性,完全受控(完全依靠props去更新组件),非受控(数据只保存在组件内部的 state )
常见的错误就是把两者混为一谈。当一个派生 state 值也被 setState方法更新时,这个值就不是一个单一来源的值了。例如控制Dialog是否显示的时候,我们通过props可以在组件外部控制Dialog是否显示,但是如果我们也想在组件内部改变这个状态,对组件来说,这个数据是多来源的,导致的问题就是组件管理混乱。
-
受控组件: 我们通过props可以在组件外部控制。不要直接复制(mirror) props 的值到 state 中,而是去实现一个受控的组件,然后在父组件里合并两个值。比如,不要在子组件里被动的接受 props.value 并跟踪一个临时的 state.value,而要在父组件里管理 state.draftValue 和 state.committedValue,直接控制子组件里的值。这样数据才更加明确可预测。
-
不受控的组件,当你想在 prop 变化(通常是 ID )时重置 state 的话,可以选择一下几种方式: 建议: 重置内部所有的初始 state,使用 key 属性 选项一:仅更改某些字段,观察特殊属性的变化(比如 props.userID)。 选项二:使用 ref 调用实例方法。
所以,设计组件时,重要的是确定组件是受控组件还是非受控组件