Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Defer adding editorKey until after initial render #822

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/universal/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "presets": ["react"] }
2 changes: 2 additions & 0 deletions examples/universal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
static
node_modules
6 changes: 6 additions & 0 deletions examples/universal/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var React = require('react');
var ReactDom = require('react-dom');

var SimpleEditor = require('./editor.js').SimpleEditor;

ReactDom.render(<SimpleEditor />, document.getElementById('react-content'));
31 changes: 31 additions & 0 deletions examples/universal/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const Draft = require('draft-js');
const React = require('react');

class SimpleEditor extends React.Component {
constructor(props) {
super(props);

this.state = {editorState: Draft.EditorState.createWithContent(emptyContentState)};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
const {Editor} = Draft;
const {editorState} = this.state;
return <Editor placeholder="heyyyyy" editorKey="foobaz" editorState={editorState} onChange={this.onChange} />;
}
}
module.exports = {
SimpleEditor: SimpleEditor,
};

const emptyContentState = Draft.convertFromRaw({
entityMap: {},
blocks: [
{
text: '',
key: 'foo',
type: 'unstyled',
entityRanges: [],
},
],
});
26 changes: 26 additions & 0 deletions examples/universal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var React = require('react');
var ReactDOMServer = require('react-dom/server');

var { SimpleEditor } = require('./editor.js');

var express = require('express');

var app = express();

app.use('/static', express.static('static'));

app.get('/', (req, res) => {
const rendered = ReactDOMServer.renderToString(<SimpleEditor />);
const page = `<!doctype html>
<html>
<body>
<div id="react-content">${ rendered }</div>
<script src="/static/bundle.js"></script>
</body>
</html>
`;
res.send(page);
});

app.listen(3003);
console.log('app now listening at http://localhost:3003');
24 changes: 24 additions & 0 deletions examples/universal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "universal",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"draft-js": "file:../../",
"express": "^4.14.0",
"immutable": "^3.8.1",
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babelify": "^7.3.0",
"browserify": "^13.1.1"
},
"scripts": {
"build": "mkdir -p static; browserify client.js -t babelify -o static/bundle.js",
"start": "babel-node index.js",
"demo": "npm run build && npm run start"
}
}
29 changes: 29 additions & 0 deletions examples/universal/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Universal rendering

Draft is well suited for universal (isomorphic) rendering contexts:

Here, we have three files:

* editor.js
A simple draftjs editor exported as `<SimpleEditor />`
* client.js
A simple clientside entrypoint that clientside renders the index page route's logic into a `#react-content` div.
* index.js
A simple express server that prerenders a <SimpleEditor /> in the `#react-content` div

you can run this by first building draft-js and then installing this demo's dependencies

```bash
# in draft-js folder
yarn
pushd examples/universal
yarn
```

then, run

`npm run demo`

which will open a server listening on [http://localhost:3003](http://localhost:3003)

visiting the main route will return a simple unstyled draft editor but the client, on re-rendering the `<SimpleEditor />` will complain that there is a mismatch between the server rendered content and the client-rendered content.
23 changes: 15 additions & 8 deletions src/component/base/DraftEditor.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const handlerMap = {

type State = {
containerKey: number,
editorKey: string,
};

/**
Expand Down Expand Up @@ -85,7 +86,7 @@ class DraftEditor extends React.Component {
_dragCount: number;
_internalDrag: boolean;
_editorKey: string;
_placeholderAccessibilityID: string;
_placeholderAccessibilityPrefix: string;
_latestEditorState: EditorState;
_pendingStateFromBeforeInput: void | EditorState;

Expand Down Expand Up @@ -121,6 +122,7 @@ class DraftEditor extends React.Component {
setClipboard: (clipboard: ?BlockMap) => void;
getClipboard: () => ?BlockMap;
getEditorKey: () => string;
getAccessibilityId: () => string;
update: (editorState: EditorState) => void;
onDragEnter: () => void;
onDragLeave: () => void;
Expand All @@ -132,8 +134,8 @@ class DraftEditor extends React.Component {
this._clipboard = null;
this._handler = null;
this._dragCount = 0;
this._editorKey = generateRandomKey();
this._placeholderAccessibilityID = 'placeholder-' + this._editorKey;

this._placeholderAccessibilityPrefix = 'placeholder-';
this._latestEditorState = props.editorState;

this._onBeforeInput = this._buildHandler('onBeforeInput');
Expand Down Expand Up @@ -165,13 +167,17 @@ class DraftEditor extends React.Component {
this.restoreEditorDOM = this._restoreEditorDOM.bind(this);
this.setClipboard = this._setClipboard.bind(this);
this.getClipboard = this._getClipboard.bind(this);
this.getEditorKey = () => this._editorKey;
this.getEditorKey = () => this.state.editorKey || this.state.editorKey;
this.getAccessibilityId = () => this._placeholderAccessibilityPrefix + this.state.editorKey;
this.update = this._update.bind(this);
this.onDragEnter = this._onDragEnter.bind(this);
this.onDragLeave = this._onDragLeave.bind(this);

// See `_restoreEditorDOM()`.
this.state = {containerKey: 0};
this.state = {
containerKey: 0,
editorKey: props.editorKey || '',
};
}

/**
Expand Down Expand Up @@ -203,7 +209,7 @@ class DraftEditor extends React.Component {
text={nullthrows(this.props.placeholder)}
editorState={this.props.editorState}
textAlignment={this.props.textAlignment}
accessibilityID={this._placeholderAccessibilityID}
accessibilityID={this.getAccessibilityId()}
/>
);
}
Expand Down Expand Up @@ -238,7 +244,7 @@ class DraftEditor extends React.Component {
}
aria-autocomplete={readOnly ? null : this.props.ariaAutoComplete}
aria-describedby={
this._showPlaceholder() ? this._placeholderAccessibilityID : null
this._showPlaceholder() ? this.getAccessibilityId() : null
}
aria-expanded={readOnly ? null : this.props.ariaExpanded}
aria-haspopup={readOnly ? null : this.props.ariaHasPopup}
Expand Down Expand Up @@ -281,7 +287,7 @@ class DraftEditor extends React.Component {
{...DefaultDraftInlineStyle, ...this.props.customStyleMap}
}
customStyleFn={this.props.customStyleFn}
editorKey={this._editorKey}
editorKey={this.state.editorKey}
editorState={this.props.editorState}
/>
</div>
Expand All @@ -303,6 +309,7 @@ class DraftEditor extends React.Component {
if (isIE) {
document.execCommand('AutoUrlDetect', false, false);
}
this.setState({editorKey: generateRandomKey()});
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/component/base/DraftEditorProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ export type DraftEditorProps = {
// an element tag and an optional react element wrapper. This configuration
// is used for both rendering and paste processing.
blockRenderMap: DraftBlockRenderMap,

// Provide a custom key for this editor instance.
// If you have multiple draft-js instances, you should set this key so that
// aria-attributes will be able to uniquely identify the correct editor.
editorKey?: string
};

export type DraftEditorDefaultProps = {
Expand Down