Home > database >  react javascript image cropper Cannot read properties of null
react javascript image cropper Cannot read properties of null

Time:12-04

Im trying to get this code for image browsing then cropping the browsed image working:

This is the supposed code to be working:

import "./styles.css";
import React, { useState } from "react";
import ReactCrop from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css'


export default function App() {
  const [src, selectFile] = useState(null);

  const onImageChange = (event) => {
    selectFile(URL.createObjectURL(event.target.files[0]));
  };

  const [image, setImage] = useState(null);
  const [crop, setCrop] = useState({ aspect: 16 / 9 });
  const [result, setResult] = useState(null);
  function getCroppedImg(){
    const canvas = document.createElement('canvas');
    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;
    canvas.width = crop.width;
    canvas.height = crop.height;
    const ctx = canvas.getContext('2d');
    ctx.drawImage
    (
      image,
      crop.x * scaleX,
      crop.y * scaleY,
      crop.width * scaleX,
      crop.height * scaleY,
      0,
      0,
      crop.width,
      crop.height,
    );
    
    const base64Image = canvas.toDataURL('image/jpeg');
    setResult(base64Image)

  }



  return (
    <div className="container">
      <div className='row'>
    <div className='col-6'>
    <input type="file" accept ='image/*' onChange={onImageChange}/>
</div>
{src && <div className='col-6'>
<ReactCrop src={src} onImageLoaded={setImage} crop={crop} onChange={setCrop} />
<button className='btn btn-danger' onClick={getCroppedImg} > Crop Image </button>
  </div>}
  {result && <div className='col-6'> <img src={result} alt='Cropped Image' className='img-fluid' /> 
  </div>}
  </div>
</div>
  );
}

You can use this sandbox link to immediately test and debug the code and see the error, code testing in sandbox

This full code is not mainly mine, I have been following this tutorial on youtube as im trying to get it working to learn and use it on my main project, But i cannot get it working as in there this error, which is not actually in the tutorial as im not even missing any line of code so i cannot understand why this error happening, appreicated to make me understand why it happened. this is the yt link: yt tutorial code

Also to add, When i try to browse the image in the current code it doesn't work so I actually tried to fix it by adding this line

<img src={src} />

under the it actually started to work for showing the image, but the cropping functionality is not working.

CodePudding user response:

The error you're seeing may be related to how the code is using React's useState hook.

In React, a hook is a special function that lets you "hook into" React features from your functional components. The useState hook is a way to add state to a functional component. It takes an initial value for the state and returns an array with two items: the current state value and a function to update the state.

In the code you posted, useState is being used to create two state variables: src and image. Here's how the code sets up the initial values for these state variables:

const [src, selectFile] = useState(null);
const [image, setImage] = useState(null);

The first useState call sets up src with an initial value of null, and the second useState call sets up image with an initial value of null.

The error you're seeing may be related to how these state variables are being used in the code. For example, the code is trying to set the src state variable when the user selects a file:

const onImageChange = (event) => {
  selectFile(URL.createObjectURL(event.target.files[0]));
};

Here, the onImageChange function is being passed to the onChange attribute of an <input type="file"> element. When the user selects a file, the onImageChange function is called, which updates the src state variable using the selectFile function that was returned by the useState call.

It's possible that the error you're seeing is related to how the src state variable is being used in the code. For example, the code is using the src state variable to set the src attribute of an <img> element:

{src && <img src={src} />}

This code uses the "short-circuit" operator (&&) to only render the <img> element if src is truthy (i.e. not null or undefined). If src is null or undefined, the <img> element will not be rendered.

If the error you're seeing is related to the src state variable, it may be because the src state variable is not being properly initialized, or because the src state variable is being set to null or undefined at some point in the code.

I would recommend carefully reviewing the code and making sure that the src state variable is being initialized with a non-null value, and that it is not being set to null or undefined at any point in the code. You may also want to check the React documentation for more information on using the useState hook.

CodePudding user response:

The error you are seeing is because image is null when you try to access its properties in the getCroppedImg function. This happens because the image state is not set until the onImageLoaded prop of the ReactCrop component is called, which only happens when the image is loaded. However, the getCroppedImg function is called before the image is loaded, so image is still null at that point.

One way to fix this would be to check if image is null before trying to access its properties in the getCroppedImg function. You can do this by adding a conditional statement like this:

function getCroppedImg(){
  if (image) {
    // rest of the code
  }
}

Alternatively, you can delay calling the getCroppedImg function until after the image is loaded. To do this, you can pass a callback function to the onImageLoaded prop of the ReactCrop component, and call the getCroppedImg function from inside that callback. This way, the getCroppedImg function will be called after the image state has been set, so it will not be null at that point.

Here's an example of how you can do this:

function App() {
  const [src, selectFile] = useState(null);

  const onImageChange = (event) => {
    selectFile(URL.createObjectURL(event.target.files[0]));
  };

  const [image, setImage] = useState(null);
  const [crop, setCrop] = useState({ aspect: 16 / 9 });
  const [result, setResult] = useState(null);

  function getCroppedImg(){
    const canvas = document.createElement('canvas');
    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;
    canvas.width = crop.width;
    canvas.height = crop.height;
    const ctx = canvas.getContext('2d');
    ctx.drawImage
    (
      image,
      crop.x * scaleX,
      crop.y * scaleY,
      crop.width * scaleX,
      crop.height * scaleY,
      0,
      0,
      crop.width,
      crop.height,
    );
    
    const base64Image = canvas.toDataURL('image/jpeg');
    setResult(base64Image)
  }

  return (
    <div className="container">
      <div className='row'>
    <div className='col-6'>
    <input type="file" accept ='image/*' onChange={onImageChange}/>
</div>
{src && <div className='col-6'>
<ReactCrop
  src={src}
  onImageLoaded={setImage}
  crop={crop}
  onChange={setCrop}
  onImageLoaded={() => getCroppedImg()}
/>
<button className='btn btn-danger' onClick={getCroppedImg} > Crop Image </button>
  </div>}
  • Related