ReactNative 图片缓存(自定义组件、用于列表纯展示,不涉及更新)

涉及可更新的组件看着里 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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容