升级到React 17.0.2后React.cloneElement无法访问自定义props问题
问题根因
React Native 0.66 版本对内置原生组件的Prop传递逻辑做了优化,会默认过滤掉组件官方未定义的非标准Prop。你自定义的colorScheme不属于Text组件官方支持的Prop,所以在内部render执行的时候就被丢弃了,自然无法从origin.props中读取到该属性。
可行解决方案
方案1:直接读取render函数的入参props(改动最小,可快速修复)
你重写的Text.render函数的第一个参数就是组件接收的原始props,不会被RN内部的过滤逻辑影响,直接从入参取值即可,修改后代码如下:
const React = require('react') const { Platform, Text } = require('react-native') const colorThemes = require('galarm-config').colorThemes const defaultFontProperties = { ...Platform.select({ android: { fontFamily: 'Roboto', fontSize: 16 }, ios: { fontSize: 16 } }) } const oldRender = Text.render if (oldRender) { Text.render = function (props, ...restArgs) { // 直接从入参获取原始传入的自定义prop const colorScheme = props.colorScheme const origin = oldRender.call(this, props, ...restArgs) console.tron.log('text color scheme', colorScheme, props.children) return React.cloneElement(origin, { style: [ defaultFontProperties, // 增加兜底逻辑避免未传colorScheme时报错 colorScheme ? { color: colorThemes.getColorTheme(colorScheme).textColor } : {}, origin.props.style ] }) } }
该方案不需要修改业务侧任何调用代码,升级后即可直接生效。
方案2:封装自定义Text组件(长期更稳定的方案)
重写内置组件的render方法属于hack行为,后续RN版本升级仍可能出现兼容问题,更稳妥的方式是封装全局通用的自定义Text组件,替换所有业务代码中原生Text的引用:
// 通用组件文件 components/AppText.js import React from 'react' import { Text, Platform } from 'react-native' import { colorThemes } from 'galarm-config' const defaultFontProperties = Platform.select({ android: { fontFamily: 'Roboto', fontSize: 16 }, ios: { fontSize: 16 } }) const AppText = ({ colorScheme, style, ...restProps }) => { return ( <Text style={[ defaultFontProperties, colorScheme ? { color: colorThemes.getColorTheme(colorScheme).textColor } : {}, style ]} {...restProps} /> ) } export default AppText
后续业务代码统一用import AppText from 'components/AppText'替代原生Text引入即可,完全不受RN底层逻辑变更影响。
后续同类问题排查思路
如果之后再遇到自定义Prop丢失的问题,可按以下顺序排查:
- 先打印组件render函数的入参,确认自定义Prop是在接收时就丢失,还是内部处理后丢失
- 查看对应版本RN的更新日志,确认对应组件是否有Prop过滤相关的变更
- 优先从上层入参获取原始数据,不要依赖组件内部render返回元素的props
内容的提问来源于stack exchange,提问作者Varun Gupta
相关产品推荐
相关产品推荐

