React Native Web 常见问题解决方案
前言
总结一下在给公司react-native项目使用react-native-web添加网页端支持时遇到的一些问题,至于添加 WEB 支持的方案可查看如何让 React Native 项目支持 WEB 网页端。
undefined (reading 'style')
Uncaught TypeError: Cannot read properties of undefined (reading 'style')
webpack构建时没有输出错误,在浏览器的日志中提示不能在undefined上读取style属性。
这是由于react-native0.62 版本移出了propTypes,可见0.62 Breaking changes,因此react-native-web也同样移出了propTypes。
所以ViewPropTypes、Text.propTypes等都是不存在的,而一些三分包中并没有跟随着改变,就导致了这个问题,比如react-native-easy-toast 2.0库中:
import {
View,
ViewPropTypes as RNViewPropTypes,
} from 'react-native'
const ViewPropTypes = RNViewPropTypes || View.propTypes;
Toast.propTypes = {
style: ViewPropTypes.style,
}
解决方案
修改react-native-web依赖包中的文件,添加需要的propTypes,例子可见react-native-web-example/patches。
node_modules/react-native-web/dist/index.js中添加导出:
export const ViewPropTypes = { style: () => {} };
node_modules/react-native-web/dist/exports/Image/index.js中添加:
Image.propTypes = { style: () => {}, source: () => {}};
node_modules/react-native-web/dist/exports/Text/index.js中添加:
Text.propTypes = { style: () => {} };
推荐使用patch-package创建补丁文件,方便管理依赖包的修改。
安装patch-package依赖
npm i patch-package
或yarn add patch-package。
创建补丁文件
npx patch-package react-native-web
或yarn patch-package react-native-web。
更多使用请看它的官方文档patch-package。
__DEV__is not defined
Uncaught ReferenceError: __DEV__ is not defined
一些依赖库使用到__DEV__的环境变量,如react-native-gesture-handler库,在react-native中它是存在的,但是我们用webpack打包时没有定义这个变量,所以我们添加一下配置就可以了。
解决方案
在webpack配置文件添加DefinePlugin插件来定义__DEV__变量:
const webpack = require('webpack')
return {
plugins: [
new webpack.DefinePlugin({
__DEV__: true
}),
],
}
你也可以根据process.env.NODE_ENV去设置__DEV__的值,不过影响并不大。
图片不显示
在react-native运行原生应用时正常显示,但是网页端不显示,主要是因为在使用Image组件时没有设置图片的宽高属性,或者在webpack的图片加载器没有设置esModule: false。
解决方案
建议在webpack解析图片时直接使用react-native-web-image-loader加载器,它可以将图片素材解析成react-native需要的对象,包含了width、height等属性。
return {
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
options: {
name: '[name].[hash:8].[ext]',
outputPath: 'images',
scalings: { '@2x': 2, '@3x': 3 },
esModule: false,
},
loader: 'react-native-web-image-loader',
}
],
},
}
样式失效或异常
网页端显示效果和原生APP显示不一样,或者从StyleSheet.create创建的样式对象取值报错,这是因为react-native-web解析StyleSheet.create方法创建的样式后是一个样式id,是一个number数字并不是对象,请看下方例子:
import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
const styles = StyleSheet.create({
container: {
flex: 1
},
textWrapper: {
width: 100
}
})
const Example = () => {
console.log(styles.container)
const { width } = styles.textWrapper
console.log(width)
return (
<View style={styles.container}>
<Text style={styles.textWrapper}>
Hello, Anand's Blog!
</Text>
</View>
)
}
export default Example
在react-native-web上StyleSheet.create返回的是一个样式对象的id,是为了优化性能。
解决方案
所以,如果项目存在从样式对象里取值,你需要使用StyleSheet.flatten方法包裹一下:
console.log(StyleSheet.flatten(styles.container))
const { width } = StyleSheet.flatten(styles.textWrapper)
console.log(width)
StyleSheet.flatten方法可以让样式id取得真正的样式对象。
使用 Nodejs 内建模块
比如公司的项目使用了jwt-simple库,这个库用到了crypto模块,就需要让网页上也能使用,通常使用crypto-browserify就可以了。
解决方案
webpack 5不会自动添加node的内建模块,我们通过配置fallback进行添加。
return {
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
vm: require.resolve("vm-browserify"),
},
extensions: ['.web.js', '.js'],
},
}
自己安装下用到的依赖,另外,如果使用了rn-nodeify对依赖进行了hack的话,在运行网页端时需要重新装依赖。
Buffer is not defined
Uncaught ReferenceError: Buffer is not defined
解决方案
使用webpack提供的ProvidePlugin插件配置一下,让项目使用Buffer时调用依赖buffer库的Buffer对象。
return {
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser',
}),
],
}
字体资源缺失
比如依赖库react-native-vector-icons会使用到ttf字体进行图标显示,如果缺失字体就会只显示一个方块。
解决方案
首先我们需要将字体文件通过copy-webpack-plugin插件拷贝到打包后到文件夹里让网页端可以请求到。
return {
plugins: [
new CopyPlugin({
patterns: [
{ from: getResolvePath('node_modules/react-native-vector-icons/Fonts/Ionicons.ttf') },
{ from: getResolvePath('node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf') },
],
}),
],
}
然后在项目引入的index.css文件添加@font-face:
import 'index.css'
@font-face {
src: url(/Ionicons.ttf);
font-family: Ionicons;
}
Alert 方法无效
到现在react-native-web 0.17.1版本,Alert方法也是没用实现的,是一个空壳,可见react-native-web#1026状态,所以你在使用Alert.alert这些方法时,实际是没用任何作用的。
解决方案
我们可以自己实现一个简单的Alert或者使用另外一个代替react-native-web的Alert。因为使用alert方法会阻塞应用,不推荐使用,我们可以使用Modal组件进行显示。
首先修改webpack配置,通过alias别名让使用Alert时不使用react-native-web库导出的,而使用我们自定义的组件。
return {
resolve: {
alias: {
'react-native-web/dist/exports/Alert': resolvePath('web/polyfills/Alert')
},
},
}
实现一个简单的Modal组件,可参考react-native-web-example案例。
版权声明:
Anand's Blog文章皆为站长Anand Zhang原创内容,转载请注明出处。
包括商业转载在内,注明下方要求的文章出处信息即可,无需联系站长授权。
请尊重他人劳动成果,用爱发电十分不易,谢谢!
请注明出处:
本文出自:Anand's Blog
本文永久链接:https://anandzhang.com/posts/frontend/21