5

I commented that I was reading the official documentation a lot, and I fully understand the concept and functioning of this. The problem is that it costs me a bit more to apply it in reality. So I started to practice and I came across something that puzzled me, I want to create a button that loads an image and shows the preview of it. However, this consists of some steps such as;

  • verify that the image has been uploaded correctly
  • create a fileReader
  • update the status of my application (path, and name of the image)
  • show the image

This would look like this:

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) } } 

I tried to create an action and that the payload is image Name and imageFile but I do not know where to put the reader ...

this is my component currently:

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);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Any correction is welcome ... Thanks!

1
  • why don't you just pass reader.result to redux action creator? Commented May 26, 2018 at 17:01

3 Answers 3

2

Why don't you just pass result from FileReader to action creator?

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 }) 

side note - you can't pass events to redux as SyntheticEvents gets nullified.

However, if you want to make this outside of component you need to do it in action creator - don't do it in reducer as they need to be pure without any side-effects. You will also need some kind of middleware to do it - the simplest yet enough for this would be redux-thunk - which allows you to return a function from your action creators:

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; } } 
Sign up to request clarification or add additional context in comments.

2 Comments

It doesn't work. dispatch is undefined in the action creator.
@dbow you will need redux-thunk middlewarr
2

I have a similar problem, I would do it that way. But I'm not sure...

action.js

function loadImage(event){ if (event.target.files && event.target.files[0]){ let file = event.target.files[0]; let fileName = file.name } return { type: LOAD_IMAGE, payload: { imageFile: file, imageFileName: fileName } } } 

1 Comment

i think that, but i dont know where to put 'new FileReader' and 'reader.readDataAsURL(file)', etc
0

It worked for me this way. I had to import store to use dispatch in the promise.

action creator

import store from '../store/index'; export const UPLOAD_FILE = 'UPLOAD_FILE'; export function uploadTextFile(file) { new Promise((resolve, reject) => { let reader = new FileReader(); reader.onloadend = () => { resolve(reader.result) }; reader.readAsText(file); }).then(result => store.dispatch({ type: UPLOAD_FILE, payload: result} )); } 

store

import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from '../reducers/index'; const store = createStore(rootReducer, applyMiddleware(thunk)); export default store; 

component (partly code, redux binding)

// ... function mapDispatchToProps(dispatch) { return bindActionCreators({ uploadTextFile }, dispatch); } export default connect(null, mapDispatchToProps)(YourComponentName); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.