如何在 Redux 中集成 FileReader?

Met*_*ode 5 javascript reactjs redux

我评论说我阅读了很多官方文档,我完全理解它的概念和功能。问题是我在现实中应用它会花费更多。所以我开始练习,我遇到了一些让我感到困惑的事情,我想创建一个按钮来加载图像并显示它的预览。但是,这包括一些步骤,例如;

  • 验证图片是否已正确上传
  • 创建一个文件阅读器
  • 更新我的应用程序的状态(图像的路径和名称)
  • 显示图像

这看起来像这样:

onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
        let reader = new FileReader();
        let file = event.target.files[0];

        reader.onloadend = () => {
            this.setState({
                imageFile: file,
                imageName: file.name
            });
        }   
        reader.readAsDataURL(file)
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图创建一个动作,有效载荷是图像名称和图像文件,但我不知道把阅读器放在哪里......

这是我目前的组件:

onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
        let reader = new FileReader();
        let file = event.target.files[0];

        reader.onloadend = () => {
            this.setState({
                imageFile: file,
                imageName: file.name
            });
        }   
        reader.readAsDataURL(file)
    }
}
Run Code Online (Sandbox Code Playgroud)
import React, { Component } from "react";
import ImageModalForm from "../../../Commons/components/ImageModalForm";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { loadImage } from "../../actions";

const faceImage = require("../../../../img/face5.gif");

class ThumbnailComp extends Component {
  onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
      let reader = new FileReader();
      let file = event.target.files[0];

      reader.onloadend = () => {
        this.setState({
          imageFile: file,
          imageName: reader.result
        });
      };
      reader.readAsDataURL(file);
    }
  }

  render() {
    return (
      <ImageModalForm
        imageFile={this.props.imageFile}
        imageName={this.props.imageName}
        onImageChange={this.onImageChange}
      />
    );
  }
}

function mapStateToProps(state) {
  return {
    image: state.image
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ loadImage }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(ThumbnailComp);
Run Code Online (Sandbox Code Playgroud)

欢迎任何更正......谢谢!

Tom*_*zyk 2

为什么不将结果从 FileReader 传递给操作创建者?

onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
      let reader = new FileReader();
      let file = event.target.files[0];

      reader.onloadend = () => {
        this.props.loadImage(reader.result)
      };
      reader.readAsDataURL(file);
    }
}

// action creator
const loadImage = (result) => ({ type: LOAD_IMAGE, result })
Run Code Online (Sandbox Code Playgroud)

旁注 - 你不能将事件传递给 redux,因为SyntheticEvents 会被 nullified

但是,如果您想在组件之外进行此操作,则需要在操作创建器中执行此操作 - 不要在减速器中执行此操作,因为它们需要纯净且没有任何副作用。您还需要某种中间件来完成此操作 - 最简单但足够的中间件是redux-thunk - 它允许您从操作创建者返回一个函数:

onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
      let file = event.target.files[0];
      this.props.loadImage(file)
    }
}

// action creator
const loadImage = file => dispatch => {
  let reader = new FileReader();

  reader.onloadend = () => {
    dispatch({
      type: 'SET_IMAGE_IN_REDUCER',
      image: reader.result
    });
  };
  reader.readAsDataURL(file);
}


// example reducer
const initialState = { image: null };
function reducer(state = initialState, action) {
  switch(action.type) {
    case 'SET_IMAGE_IN_REDUCER': 
      return { ...state, image: action.image }
    ...
    default:
      return state;
  }
}
Run Code Online (Sandbox Code Playgroud)