Hiroaki Machida
Hiroaki Machida

Reputation: 1090

React update state in a new form

How can I update the state in a new form? I want to convert an image into base64 when uploaded and push it to the firebase.

However, I got an TypeError: this.setState is not a function error.

I also tried to update the value of input, but didn't work. document.getelementbyid("image").value = reader.result

Thank you!

import React from 'react'
import PropTypes from 'prop-types'
import { Formik, Field, Form } from 'formik'
import { TextField } from 'formik-material-ui'
import { makeStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogTitle from '@material-ui/core/DialogTitle'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import styles from './NewProjectDialog.styles'

const useStyles = makeStyles(styles)

function NewProjectDialog({ onSubmit, open, onRequestClose }) {
  const classes = useStyles()

  function handleSubmit(values, { setSubmitting }) {
    return onSubmit(values).then(() => {
      setSubmitting(false)
    })
  }

  function previewFile() {
    const preview = document.querySelector('img');
    const file = document.querySelector('input[type=file]').files[0];
    const reader = new FileReader();

    reader.addEventListener("load", function () {
      // convert image file to base64 string
      preview.src = reader.result;
      this.setState({image: reader.result})
    }, false);

    if (file) {
      reader.readAsDataURL(file);
    }

    this.previewFile = this.preview.bind(this)
  }

  return (
    <Dialog open={open} onClose={onRequestClose}>
      <DialogTitle id="new-project-dialog-title">New Project</DialogTitle>
      <Formik initialValues={{ name: '' }} onSubmit={handleSubmit}>
        {({ errors, isSubmitting }) => (
          <Form className={classes.root}>
            <DialogContent>
              <Field
                name="isbn"
                label="ISBN"
                component={TextField}
                margin="normal"
                fullWidth
              />
              <Field
                name="title"
                label="Title"
                component={TextField}
                margin="normal"
                fullWidth
              />
              <Field
                name="status"
                label="Status"
                component={TextField}
                margin="normal"
                fullWidth
              />
              <Field
                name="price"
                label="Price"
                component={TextField}
                margin="normal"
                fullWidth
              />
              <Field
                id="image"
                name="image"
                component={TextField}
                style={{display:"none"}}
              />
              <input type="file" onChange={previewFile}/>
              <img src="" height="200" alt="Image preview..."></img>
            </DialogContent>
            <DialogActions>
              <Button onClick={onRequestClose} color="secondary">
                Cancel
              </Button>
              <Button type="submit" color="primary" disabled={isSubmitting}>
                {isSubmitting ? 'Creating...' : 'Create'}
              </Button>
            </DialogActions>
          </Form>
        )}
      </Formik>
    </Dialog>
  )
}

NewProjectDialog.propTypes = {
  onSubmit: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  onRequestClose: PropTypes.func.isRequired
}

export default NewProjectDialog


I modified the code but the image was not stored in the firebase...

function NewProjectDialog({ onSubmit, open, onRequestClose }) {
  const classes = useStyles()
  const [image, setImage] = useState({image: null});

(Omitted)

  function previewFile() {
    const preview = document.querySelector('img');
    const file = document.querySelector('input[type=file]').files[0];
    const reader = new FileReader();

    reader.addEventListener("load", function () {
      // convert image file to base64 string
      preview.src = reader.result;
      setImage({image: reader.result});
    }, false);

    if (file) {
      reader.readAsDataURL(file);
    }

  }

-M0EVfPfzF1vjQ4wLXLU
createdAt: 1581881931504
createdBy: "YcGWgfdbk2hs8CcWSdtsicYncyB3"
isbn: "asdfa"
name: ""
price: "asdfasd"
status: "asfdasfd"
title: "asfdasfd"

Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text Meaningless text

Upvotes: 0

Views: 53

Answers (1)

norbitrial
norbitrial

Reputation: 15166

I guess this issue is coming from that this.setState can be used only in class based component. In function components like what you have - NewProjectDialog - you can use useState hook where you can create your state and the updater function.

What does useState return? It returns a pair of values: the current state and a function that updates it.

So you could have the defined state as:

const [image, setImage] = useState({image: null});

And instead of this.setState({image: reader.result}) you would modify as the following:

// updating value
setImage({image: reader.result});

Read further here: Using the State Hook

I hope that helps!

Upvotes: 1

Related Questions