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-native
0.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 = {
// ViewPropTypes 为 undefined
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)
// WEB 输出: number
// Native 输出: {"flex": 1}
const { width } = styles.textWrapper
console.log(width)
// WEB: undefined
// Native: 100
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))
// WEB、Native: {"flex": 1}
const { width } = StyleSheet.flatten(styles.textWrapper)
console.log(width)
// WEB、Native: 100
StyleSheet.flatten
方法可以让样式id
取得真正的样式对象。
使用 Nodejs 内建模块
比如公司的项目使用了jwt-simple
库,这个库用到了crypto
模块,就需要让网页上也能使用,通常使用crypto-browserify
就可以了。
解决方案
webpack 5
不会自动添加node
的内建模块,我们通过配置fallback
进行添加。
return {
// 省略其他配置
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
// 我的项目在处理 crypto 时,还用到了 stream 和 vm
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: [
// 添加用到的字体,或者直接将 Fonts 文件夹全拷贝过来
{ 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
:
// index..web.js
import 'index.css'
/* 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