【问题标题】:Refs is empty object {} when using correct reference pattern in React with TypeScript在 React with TypeScript 中使用正确的引用模式时,Refs 是空对象 {}
【发布时间】:2019-01-14 09:08:09
【问题描述】:

问题:

我正在尝试从react-cropper 中创建一个在 TypeScript 中工作的示例。该示例适用于 .JSX,并且有 Typings,所以我认为它可以很好地工作,对 .JSX 代码进行一些更改。

让我印象深刻的一件棘手的事情是 TypeScript 和 React 中的参考模式。但是,我发现了这个惊人的 question on SO,我已经按照它来设置所有内容。

预期:

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

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

实际:

cropImage() 函数中的console.log(this) 显示refs 为空,即使我按照上面的示例进行操作。

尝试使用现在已弃用的使用字符串的引用模式告诉我this 具有指向cropImage() 函数的引用标题。但是,由于 TS 是强类型的,我无权访问getCroppedCanvas()

代码:

import * as React from "react";
import Cropper from 'react-cropper';
import 'cropperjs/dist/cropper.css';

export class ImageEditor extends React.Component<any, any> {
    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 (
            <div>
                <div style={{ width: '100%' }}>
                    <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}}
                    />
                </div>
                    <div>
                        <div className="box" style={{ width: '50%', float: 'right' }}>
                            <h1>Preview</h1>
                            <div className="img-preview" style={{ width: '100%', float: 'left', height: 300 }} />
                        </div>
                    <div className="box" style={{ width: '50%', float: 'right' }}>
                        <h1>
                        <span>Crop</span>
                        <button onClick={this.cropImage} style={{ float: 'right' }}>
                            Crop Image
                        </button>
                        </h1>
                        <img style={{ width: '100%' }} src={this.state.cropResult} alt="cropped image" />
                    </div>
                </div>
            </div>
        );
    }
} 

编辑:

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

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

{
  "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:

{
    "name": "@types/react-cropper",
    "dependencies": {
    }
}

【问题讨论】:

    标签: javascript reactjs typescript


    【解决方案1】:

    看起来您正在使用回调模式和RefObject 模式的奇怪组合。如果你想使用RefObject,你应该将RefObject作为ref属性传递,即:

    ref={this.cropRef}
    

    如果你想使用回调,那么声明应该是:

    private cropRef : Cropper;
    

    你会使用this.cropRef.getCroppedCanvas()而不是this.cropRef.current.getCroppedCanvas()

    【讨论】:

    • 我也是这么想的,但是当我这样做时,基本上到处都会出错。如果我使用RefObject 模式,我的代码会在this.cropRef.getCroppedCanvas() 上中断,因为该方法在RefObject&lt;Cropper&gt; 类型和Cropper 元素中的ref 上不存在。这是因为RefObject 缺少属性(例如align)。这是错误Type 'ReactCropper' is not assignable to type 'HTMLImageElement'. Property 'align' is missing in type 'ReactCropper'. 的一部分
    • 如果您使用RefObject 模式,那么您应该保留current 以取消引用this.cropRef.current.getCroppedCanvas() 中的RefObject。你在尝试哪种方式?
    • 使用RefObject 模式我正在使用current,它解决了访问getCroppedCanvas() 的问题。但是,我无法在元素上设置引用
    • 你用过ref={this.cropRef}吗?你遇到了什么错误?
    • 最后我自己实际尝试过,看起来react-cropper 的类型定义有错误:React.HTMLProps&lt;HTMLImageElement&gt; 应该替换为React.AllHTMLAttributes&lt;HTMLImageElement&gt;。可以使用this procedure在本地修改类型定义。
    猜你喜欢
    • 1970-01-01
    • 2020-10-19
    • 2020-08-10
    • 2020-01-14
    • 2019-12-16
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    相关资源
    最近更新 更多