关于javascript:在带有TypeScript的React中使用正确的引用模式时,引用是空对象{}

Refs is empty object {} when using correct reference pattern in React with TypeScript

问题:

我正在尝试从react-cropper的TypeScript中创建一个示例。该示例在.JSX上运行良好,并且具有键入功能,因此我认为只要对.JSX代码进行一些更改,它就可以很好地工作。

我想知道的棘手的事情之一是TypeScript和React中的引用模式。但是,我在SO上发现了一个令人惊讶的问题,接下来我进行了设置。

预期:

ref模式将按预期工作,并且我可以访问底层函数(从对象)。

即我期望看到this.cropRef可以访问getCroppedCanvas(在react-cropper中定义)。

实际:

cropImage()函数中的console.log(this)显示refs为空,即使我遵循上述示例。

尝试使用现在不建议使用的使用字符串的ref模式,这表明this将参考标题引入了cropImage()函数。但是,因为TS是强类型的,所以我无法访问getCroppedCanvas()

码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import * as React from"react";
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';

export class ImageEditor extends React.Component {
    private cropRef : React.RefObject<Cropper>;

    constructor(props : any) {
        super(props);
        this.state = {
            src :"",
            cropResult :""
        };

        this.cropRef = React.createRef();  
        this.cropImage = this.cropImage.bind(this);
        this.onChange = this.onChange.bind(this);
    }

    onChange(e : any) {
        e.preventDefault();
        let files;
        if (e.dataTransfer) {
            files = e.dataTransfer.files;
        } else if (e.target) {
            files = e.target.files;
        }
        const reader = new FileReader();
        reader.onload = () => {
            this.setState({ src : reader.result });
        };
        reader.readAsDataURL(files[0]);
    }

    cropImage() {
        console.log(this.refs);
        if (typeof this.cropRef.current.getCroppedCanvas() === 'undefined') {
                return;
        }
        this.setState({
            cropResult: this.cropRef.current.getCroppedCanvas().toDataURL(),
        });
    }

    render() {
        return (
           
               
                    <input type="file" onChange={this.onChange} />
                    <br />
                    <br />
                    <Cropper
                        style={{ height: 400, width: '100%' }}
                        aspectRatio={16 / 9}
                        preview=".img-preview"
                        guides={false}
                        src={this.state.src}
                        ref={(cropper : any) => { this.cropRef = cropper}}
                    />
               
                   
                       
                            Preview
                           
                       
                   
                       
                        <span>Crop</span>
                        <button onClick={this.cropImage} style={{ float: 'right' }}>
                            Crop Image
                        </button>
                       
                        <img style={{ width: '100%' }} src={this.state.cropResult} alt="cropped image" />
                   
               
           
        );
    }
}

编辑:

为react-cropper编辑了index.d.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import * as cropperjs from 'cropperjs';
import * as React from 'react';

import Data = cropperjs.Data;
import ContainerData = cropperjs.ContainerData;
import ImageData = cropperjs.ImageData;
import CanvasData = cropperjs.CanvasData;
import CropBoxData = cropperjs.CropBoxData;
import CroppedCanvasOptions = cropperjs.CroppedCanvasOptions;
type ReactCropperProps = cropperjs.CropperOptions & React.AllHTMLAttributes<HTMLImageElement>;

interface ReactCropper extends cropperjs {} // tslint:disable-line no-empty-interface
declare class ReactCropper extends React.Component<ReactCropperProps> {
    on(eventname: string, callback: () => void): void;
}
export default ReactCropper;

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
 "name":"name",
 "version":"1.0.0",
 "description":"packages for content",
 "main":"webpack.config.js",
 "scripts": {
   "build":"webpack",
   "test":"karma start karma.unit.build.js",
   "build-test":"karma start karma.unit.js",
   "coverage":"karma start karma.coverage.js"
  },
 "author":"Joakim Bajoul Kakaei",
 "license":"ISC",
 "devDependencies": {
   "@types/chai":"^4.1.4",
   "@types/mocha":"^5.2.5",
   "@types/react":"^16.4.7",
   "@types/react-cropper":"./node_modules/react-cropper.fixed",
   "@types/react-dom":"^16.0.6",
   "@types/react-dropzone":"^4.2.0",
   "@types/sinon":"^5.0.1",
   "babel-core":"^6.26.3",
   "babel-loader":"^7.1.5",
   "chai":"^4.1.2",
   "css-loader":"^1.0.0",
   "istanbul-instrumenter-loader":"^3.0.1",
   "karma":"^2.0.5",
   "karma-chai":"^0.1.0",
   "karma-coverage":"^1.1.2",
   "karma-mocha":"^1.3.0",
   "karma-phantomjs-launcher":"^1.0.4",
   "karma-sinon":"^1.0.5",
   "karma-typescript-preprocessor2":"^1.2.1",
   "karma-webpack":"^3.0.0",
   "mocha":"^5.2.0",
   "mocha-webpack":"^1.1.0",
   "phantomjs-prebuilt":"^2.1.16",
   "sinon":"^6.1.4",
   "style-loader":"^0.21.0",
   "ts-loader":"^4.4.2",
   "ts-node":"^7.0.0",
   "typescript":"^2.9.2",
   "typings":"^2.1.1",
   "webpack":"^4.16.2",
   "webpack-cli":"^3.1.0"
  },
 "dependencies": {
   "npm":"^6.3.0",
   "react":"^16.4.1",
   "react-cropper":"^1.0.1",
   "react-dom":"^16.4.1",
   "react-dropzone":"^4.2.13"
  }
}

node_modules / react-cropper / package.json:

1
2
3
4
5
{
   "name":"@types/react-cropper",
   "dependencies": {
    }
}

看来您正在使用回调模式和RefObject模式的奇怪组合。 如果要使用RefObject,则只需将RefObject作为ref属性传递,即:

1
ref={this.cropRef}

如果要使用回调,则声明应为:

1
private cropRef : Cropper;

并且您将使用this.cropRef.getCroppedCanvas()而不是this.cropRef.current.getCroppedCanvas()