tag: [React Native]
InlineRequires
在查询资料时注意到了metro.config.json文件中的inlineRequires 配置项, 之前虽然有注意到, 但是没有去深入了解, 今天查阅了下, 发现它的作用是将 require变成内联(inline) 形式, 读者OS: "你这不是废话吗", 别着急, 然我们看几个例子:
请允许我直接抄代码注释:
// 转换之前
var Foo = require('foo');
// 转换之后
f(Foo);
// 转换之前
var Bar = require('foo').bar
g(Bar)
// 转换之后
g(require('foo').bar);
// 转换之前
const {Baz} = require('foo');
h(Baz);
// 转换之后
g(require('foo').Baz);
inlineRequires源码 上面的例子也来源于此.
对这个配置项不了解的小伙伴和笔者一样一脸懵逼, 没搞懂这个有什么用, 不过本着求真的精神笔者继续查询 inlineRequires相关的资料, 查到在 React Native 官方文档的一篇文章《RAM Bundles and Inline Requires》(英语不好的小伙伴也可以读这篇翻译好的文章).
它的主要用途是按需加载 Bundle(允许笔者用这个词, 这里表示可能是组件, 三方 lib 之类的), 但是想要按需加载, 开发者就要提供加载的条件给 RN, 那么代码很自然的就变成了
const show = false
const Component = show ? require("HumanDetecor")
render() {
if (show) {
return Component;
}
return View;
}
上面代码有些抽象, 但是相信读完 《RAM Bundles and Inline Requires》的小伙伴肯定是可以看懂的, 可以看到, 我们通过 show 变量决定要不要加载 HumanDetecor组件, 那么就要通过 require方法去加载, OK, 一切看上去很美好, 那么上生产环境试试?
const TestApp = () => {
const Component1 = useRef(null)
const Component2 = useRef(null)
const [visible, setVisible] = useState(false)
const show = () => {
Component1.current = require("HumanDetecor1")
Component2.current = require("HumanDetecor2").Test
setVisible(true)
}
return <View>
{ visible && Component1.current }
{ visible && Component2.current }
<Button title={"显示"} onPress={show}/>
</View>
}
可以发现, 需要在逻辑代码中混合使用 require, 如果我们希望所有导入都在代码顶部, 就需要使用 inlineRequires
const HumanDetecor1 = require("HumanDetecor1")
const HumanDetecor2 = require("HumanDetecor2").Test
const TestAppWithInlineRequire = () => {
const Component1 = useRef(null)
const Component2 = useRef(null)
const [visible, setVisible] = useState(false)
const show = () => {
Component1.current = HumanDetecor1
Component2.current = HumanDetecor1
setVisible(true)
}
return <View>
{ visible && Component1.current }
{ visible && Component2.current }
<Button title={"显示"} onPress={show}/>
</View>
}
可以发现, 通过 inlineRequires可以更好的组织代码.
注: 上面只是以 require举例, inlineRequires同样支持 import语法, 联想到 nextjs的 URL imports 说不定在将来的某一天可以直接在 React Native 中懒加载 url module.
react native Style property 'height' is not supported by native animated module
这个问题也算是比较常见的问题, 笔者自然是知道 height是不能和 useNativeDriver一同使用的, 本次在调试自行开发的组件 [react-native-dropdown](https://github.com/MonchiLin/react-native-dropdown/tree/next)时遇到的, 复现场景伪代码如下:
let visible = false
let animatedStyle = {}
let value = new Animated.Value(0)
useEffect(() => {
if(visible) {
value.setValue(0)
setAnimatedStyle({height: value})
Animated.timing(value, {
useNativeDriver: false,
duration: 200,
toValue: 100
})
} else {
value.setValue(100)
setAnimatedStyle({transform: { y: value }})
Animated.timing(value, {
useNativeDriver: true,
duration: 200,
toValue: 0
})
}
}, [visible])
return <Animated.View style={animatedStyle}/>
通过 visible 状态来控制动画效果, 如果为 true 则播放 height从 0 到 100 的动画, 反之则播放 transform.y 从 100 到 0 的动画, 但是就是这个简单的代码却报出了 react native Style property 'height' is not supported by native animated module 让笔者调试了很长时间.
最初笔者以为是逻辑问题, 调试了很久, 终于确定了和逻辑没关系, useNativeDriver的传参是正确的, 于是只能去看源码, 发现不管怎么设置, 这里都会去验证 style 里是否包含非原生动画属性, 只能又陷入了一段时间的 debug, 虽然没有从源码中参悟原因, 但是无意中发现了一个解决办法, 即: 重新创建 Animated.Value 实例, 虽然没有了解事情的本质, 但是中间经历了很多心路历程, 这里记录下防止别的小伙伴踩坑.
let visible = false
let animatedStyle = {}
let value = new Animated.Value(0)
useEffect(() => {
if(visible) {
// here
value = new Animated.Value(0)
setAnimatedStyle({height: value})
Animated.timing(value, {
useNativeDriver: false,
duration: 200,
toValue: 100
})
} else {
value.setValue(100)
setAnimatedStyle({transform: { y: value }})
Animated.timing(value, {
useNativeDriver: true,
duration: 200,
toValue: 0
})
}
}, [visible])
return <Animated.View style={animatedStyle}/>