在passProps中传递函数数组引发JS调用格式异常问题
这个报错Malformed call from JS: field sizes are different.我之前在RN Navigation v1的Android项目里也碰到过,根源在于React Native Navigation v1的Android端无法正确序列化传递包含函数的数组——因为passProps里的内容需要从JS层传递到原生层,而函数是不能被序列化的,数组包裹的函数会让原生的序列化逻辑出现字段不匹配的问题。
几个可行的解决方案:
1. 改用事件订阅替代直接传函数
这是最稳妥的方式,用React Native自带的DeviceEventEmitter来实现跨页面回调:
源页面代码:
import { DeviceEventEmitter } from 'react-native'; // 订阅自定义事件,处理回调逻辑 const callbackSubscription = DeviceEventEmitter.addListener('screenCallback', (payload) => { console.log('收到目标页面的回调:', payload); // 这里写你原本要在函数里执行的逻辑 }); // 跳转时只传递事件标识 navigator.push({ screen: 'anyScreen', passProps: { callbackEvent: 'screenCallback' } }); // 组件卸载时一定要取消订阅,避免内存泄漏 componentWillUnmount() { callbackSubscription.remove(); }
目标页面代码:
import { DeviceEventEmitter } from 'react-native'; // 需要触发回调时,通过事件发射器发送数据 const triggerCallback = () => { DeviceEventEmitter.emit(this.props.callbackEvent, { key: 'value' }); };
2. 用全局状态管理工具(Redux/MobX)
如果你的项目已经在用状态管理,可以把原本要通过回调处理的逻辑,改成更新全局状态,源页面监听状态变化来执行对应操作。比如用Redux的话,目标页面dispatch一个action,源页面通过connect订阅对应的state变化。
3. 升级React Native Navigation到更高版本
RN Navigation v1是比较旧的版本了,后续的v2+版本对passProps的序列化逻辑做了优化,基本解决了这类函数传递的问题。如果项目允许的话,升级到最新稳定版是一劳永逸的办法(注意升级时要按照官方文档做适配,避免其他兼容性问题)。
4. 避免传递函数数组,改用单个函数或标识
如果一定要在passProps里传递回调,尽量不要放在数组里,直接传递单个函数试试(不过v1的Android端可能还是会有问题,这个不一定靠谱),或者把函数转换成字符串标识,在目标页面根据标识调用全局注册的函数。
总结
最推荐的是方案1(事件订阅)或者方案3(升级版本),前者不需要改动项目架构,后者能从根本上解决这类序列化问题。
内容的提问来源于stack exchange,提问作者HenriC

