From the draft-js documention, one can (in vanilla React, with no typescript) setup the Draft-js environment thus, noticing that the onChange
property can be declared directly in the constructor:
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
const {editorState} = this.state;
return <Editor editorState={editorState} onChange={this.onChange} />;
}
}
However, when I try to do the same with Typescript/React (code below), I get this error
error TS2339: Property 'onChange' does not exist on type 'Main'.
class Main extends React.Component<MainProps, MainState> {
constructor(props) {
super(props);
this.state = { todos: [], editorState: EditorState.createEmpty() };
this.onChange = (editorState) => this.setState({ editorState });
}
I also tried adding onChange
as a property to the props
interface MainProps {
model: Model;
onChange: Function;
}
What is the appropriate way to declare such a function property in typescript/react?
The TypeScript docs have a great example of constructor usage: class Greeter { greeting: string; constructor(message: string) { this. greeting = message; } greet() { return "Hello, " + this. greeting; } } let greeter = new Greeter("world");
props will be undefined in the constructor, which can lead to bugs. Typically, in React constructors are only used for two purposes: Initializing local state by assigning an object to this.
Data within React Components is stored as either properties or state. Properties are the input values to the component. They are used when rendering the component and initializing state (discussed shortly). After instantiating the component, properties should be considered immutable.
In the highlighted code, you added a parameter called name of type string to your class constructor. Then, when creating a new instance of the Person class, you are also setting the value of that parameter, in this case to the string "Jane" . Finally, you changed the console. log to print the argument to the screen.
Try this:
class Main extends React.Component<MainProps, MainState> {
constructor(props) {
super(props);
this.state = { todos: [], editorState: EditorState.createEmpty() };
this.onChange = (editorState) => this.setState({ editorState });
}
onChange: (state: MainState) => void;
}
I haven't tested it, but I think it should work.
Yeah, there's a problem there that I haven't noticed, it should be:
class Main extends React.Component<MainProps, MainState> {
constructor(props) {
super(props);
this.state = { todos: [], editorState: EditorState.createEmpty() };
this.onChange = (editorState) => this.setState({
editorState: editorState
} as MainState);
}
onChange: (state: MainState) => void;
}
The type assertion (as MainState
) is needed if the todos
property isn't optional, if it is optional (todos?: any[]
) then there's no need for the assertion.
As for what seems to be duplication with the onChange
definition, it is explained in short in the Mixins part of the typescript docs, but in your example the definition in the class:
onChange: (state: MainState) => void;
let's the compiler know that instances of Main
have this method called onChange
that receives a MainState
and returns void
.
But the implementation of this method is only assigned when the instance is created in the ctor:
this.onChange = (editorState) => this.setState({ editorState });
If the definition is missing then the assignment in the ctor will produce a compilation error: property 'onChange' does not exist on type 'Main'
.
You can use handleChange method like this :
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Editor, EditorState } from 'draft-js';
interface MyEditorProps {
}
class MyEditor extends React.Component<MyEditorProps, any> {
constructor(props: MyEditorProps) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
}
handleChange(e: EditorState) {
this.setState({ editorState: e });
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={e => this.handleChange(e)} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('editor'),
);
export { MyEditor }
Alternatively, you can try it like this:
private onChange = (editorState) => this.setState({ editorState } as MainState)
just in the body of the class, where you define other class properties. I dunno, which version you're running, but this code totally works in ES2015
and TypeScript 2.0.10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With