涉及可更新的组件看着里 https://www.jianshu.com/p/f19b83e0ec33
index.js
import React, { Component, PureComponent } from 'react'
import {
View,
Image,
ImageBackground,
Platform
} from 'react-native'
import styles from './style'
import PropTypes from 'prop-types'
import CacheUtil from './CacheUtil'
import default_avatar from '../../Images/default_avatar.png'
class CacheImage extends PureComponent {
constructor(props) {
super(props)
this.state = {
imagePath: undefined, // 图片的本地地址
}
this.cacheUtil = new CacheUtil(this.props.source)
}
async componentDidMount() {
// this.props.source,先判断本地是否有缓存
// 存在-> 则返回本地路径,再赋值给state.imagePath
// 没有-> 则下载,下载完成后,返回本地路径,再赋值给state.imagePath
let result = await this.cacheUtil.existImage()
if (result.isHas) {
this.setState({
imagePath: Platform.OS ==='ios' ? result.imagePath : 'file://' + result.imagePath
})
console.log('本地图片');
} else {
this.cacheUtil.fetchImage((suc, imagPath) => {
this.setState({
imagePath: Platform.OS ==='ios' ? imagPath : 'file://' + imagPath
})
})
console.log('网络下载');
}
}
componentWillUnmount() {
// 组件销毁,如果正在下载,则取消下载
this.cacheUtil.cancelAxiosRequest()
this.cacheUtil = null
}
render() {
const { imageStyle, defaultSource } = this.props
const { imagePath } = this.state
return (
<View>
<ImageBackground
source={defaultSource}
style={[imageStyle, styles.backgroudStyle]}>
{imagePath && <Image style={{ flex: 1, }} source={{ uri: imagePath }} />}
</ImageBackground>
</View>
)
}
}
CacheImage.propTypes = {
source: PropTypes.string.require, // 图片url
defaultSource: PropTypes.any, // 默认图片
imageStyle: PropTypes.object, // 图片样式
onPress: PropTypes.func, // 点击事件
}
CacheImage.defaultProps = {
defaultSource: default_avatar //默认图片
}
export default CacheImage
style.js
import { StyleSheet } from 'react-native'
export default StyleSheet.create({
backgroudStyle: {
overflow:'hidden'
}
})
CacheUtil.js
import RNFS from 'react-native-fs';
import CryptoJS from 'crypto-js'
import axios from 'axios'
import Base64ToArraybuffer from 'base64-arraybuffer'
import React, { Component } from 'react';
export default class CacheUtil {
constructor(imageURL){
this.axiosFetchRequestCancel = null
this.imageUrl = imageURL
}
/**
* [existImage 判断图片是否存缓存]
* imageUrl [图片的网络路径]
* @return [返回是/否]
*/
existImage = async ()=>{
try {
let imagePath = this.getImagePath(this.imageUrl)
const result = await RNFS.exists(imagePath).catch(e => console.log('e',e))
return {
isHas: result,
imagePath
}
} catch (e) {
return {
isHas: false,
}
}
}
/**
* [getImagePath 获取图片的本地路径]
* imageUrl [图片的网络路径]
* @return [返回图片的本地路径]
*/
getImagePath = ()=>{
return this._getLocalPath(this.imageUrl) + this._getImageName(this.imageUrl)
}
/**
* [fetchImage 下载图片]
* imageUrl [图片的网络路径]
* @return [返回图片的本地路径]
*/
fetchImage = (callBack)=>{
// 获取远端图片
let that = this
try {
axios(this.imageUrl,
{
responseType: 'arraybuffer',
cancelToken: new axios.CancelToken(function executor(c) {
that.axiosFetchRequestCancel = c // 用于取消下载
})
}
)
.then(function(response) {
let base64 = Base64ToArraybuffer.encode(response.data)
let imagePath = that.getImagePath(that.imageUrl)
that.axiosFetchRequestCancel = null
RNFS.writeFile(imagePath, base64, 'base64').then(()=>{
callBack && callBack(true, imagePath)
}).catch(e=>{
callBack && callBack(false)
})
}).catch(error=>{
callBack && callBack(false)
});
} catch (e) {
}
}
/**
* [cancelAxiosRequest 取消axios post请求]
*/
cancelAxiosRequest = ()=>{
this.axiosFetchRequestCancel && this.axiosFetchRequestCancel('cancel')
}
/**
* [getLocalPath 获取图片缓存的文件夹]
*/
_getLocalPath = ()=>{
return RNFS.DocumentDirectoryPath + '/Avatar/'
}
/**
* [getImageSuffixName 获取图片的后缀名]
*/
_getImageSuffixName = ()=>{
let arr = this.imageUrl.split('.')
return '.' + arr[arr.length - 1]
}
/**
* [getImageMD5 获取图片MD5码,用于得到图片的本地名字]
*/
_getImageMD5 = ()=>{
return CryptoJS.MD5(this.imageUrl).toString()
}
/**
* [getImageName 获取图片的完整名字]
*/
_getImageName = ()=>{
return this._getImageMD5(this.imageUrl) + this._getImageSuffixName(this.imageUrl)
}
}
使用
// 针对列表的数据,外部View一定要设置key,不然当列表数据改变时,会出现头像不正确问题~
<View key = {item.userHeadUrl}>
<CacheImage source={ item.userHeadUrl } />
</View>
网友评论