如何从 localStorage 读取 DraftJS 状态?
How to read DraftJS state from localStorage?
我在从 localStorage 读取 Draft.js 原始内容时遇到问题。
我想使用以前存储的 rawContent 作为我的 initialState
减速器。
我认为 convertFromRaw
功能是我的问题。
我默默地暗恋(不登录到控制台),我不知道如何解决这个问题。
我坚持 Draft.js localStorage 中的原始内容:
const contentState = editorState.getCurrentContent();
const rawContent = convertToRaw(contentState);
window.localStorage.setItem(
"rawContent",
JSON.stringify(convertToRaw(rawContent))
);
然后当我试图恢复它时,我遇到了我的问题。
我认为 convertFromRaw
.
const rawContent = window.localStorage.getItem("rawContent");
if (rawContent) {
this.state.editorState = EditorState.createWithContent(
convertFromRaw(JSON.parse(rawContent))
);
} else {
this.state.editorState = EditorState.createEmpty();
}
我的临时解决方案是使用第三方转换器。
在我的例子中,我使用了 stateToMarkdown / stateFromMarkdown
来自 draft-js-export-markdown / draft-js-import-markdown
我的package.json
{
"name": "react-boilerplate",
"version": "3.7.0",
"description": "A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices",
"repository": {
"type": "git",
"url": "git://github.com/react-boilerplate/react-boilerplate.git"
},
"engines": {
"npm": ">=5",
"node": ">=8.10.0"
},
"author": "Max Stoiber",
"license": "MIT",
"scripts": {
"analyze:clean": "rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"analyze": "node ./internals/scripts/analyze.js",
"extract-intl": "node ./internals/scripts/extract-intl.js",
"npmcheckversion": "node ./internals/scripts/npmcheckversion.js",
"preinstall": "npm run npmcheckversion",
"prebuild": "npm run build:clean",
"build": "cross-env NODE_ENV=production webpack --config internals/webpack/webpack.prod.babel.js --color -p --progress --hide-modules --display-optimization-bailout",
"build:clean": "rimraf ./build",
"start": "cross-env NODE_ENV=development node server",
"start:tunnel": "cross-env NODE_ENV=development ENABLE_TUNNEL=true node server",
"start:production": "npm run test && npm run build && npm run start:prod",
"start:prod": "cross-env NODE_ENV=production node server",
"presetup": "npm i chalk shelljs",
"setup": "node ./internals/scripts/setup.js",
"clean": "shjs ./internals/scripts/clean.js",
"clean:all": "npm run analyze:clean && npm run test:clean && npm run build:clean",
"generate": "plop --plopfile internals/generators/index.js",
"lint": "npm run lint:js",
"lint:css": "stylelint './app/**/*.js'",
"lint:eslint": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts",
"lint:eslint:fix": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts --fix",
"lint:js": "npm run lint:eslint -- . ",
"lint:staged": "lint-staged",
"pretest": "npm run test:clean && npm run lint",
"test:clean": "rimraf ./coverage",
"test": "cross-env NODE_ENV=test jest --coverage",
"test:watch": "cross-env NODE_ENV=test jest --watchAll",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"prettify": "prettier --write"
},
"jest": {
"collectCoverageFrom": [
"app/**/*.{js,jsx}",
"!app/**/*.test.{js,jsx}",
"!app/app.js",
"!app/global-styles.js",
"!app/*/*/Loadable.{js,jsx}"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 40,
"functions": 50,
"lines": 50
}
},
"moduleDirectories": [
"node_modules",
"app"
],
"moduleNameMapper": {
".*\.(css|less|styl|scss|sass)$": "<rootDir>/internals/mocks/cssModule.js",
".*\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/image.js"
},
"setupTestFrameworkScriptFile": "<rootDir>/internals/testing/test-bundler.js",
"testRegex": "tests/.*\.test\.js$"
},
"lint-staged": {
"*.js": [
"npm run lint:eslint:fix",
"git add --force"
],
"*.json": [
"prettier --write",
"git add --force"
]
},
"pre-commit": "lint:staged",
"resolutions": {
"babel-core": "7.0.0-bridge.0"
},
"dependencies": {
"@babel/polyfill": "7.0.0",
"antd": "^3.13.1",
"axios": "^0.18.0",
"chalk": "2.4.1",
"compression": "1.7.3",
"connected-react-router": "4.5.0",
"cross-env": "5.2.0",
"draft-js": "^0.10.5",
"draft-js-export-html": "^1.3.3",
"draft-js-export-markdown": "^1.3.3",
"draft-js-import-html": "^1.3.3",
"draft-js-import-markdown": "^1.3.3",
"express": "4.16.4",
"fontfaceobserver": "2.0.13",
"history": "4.7.2",
"hoist-non-react-statics": "3.0.1",
"immutable": "3.8.2",
"intl": "1.2.5",
"invariant": "2.2.4",
"ip": "1.1.5",
"loadable-components": "2.2.3",
"lodash": "4.17.11",
"minimist": "1.2.0",
"prop-types": "15.6.2",
"react": "16.6.0",
"react-dom": "16.6.0",
"react-draft-wysiwyg": "^1.13.2",
"react-flexview": "^4.0.3",
"react-helmet": "5.2.0",
"react-intl": "2.7.2",
"react-logger-lib": "^1.0.5",
"react-rbac-guard": "0.0.3",
"react-redux": "5.0.7",
"react-router-dom": "4.3.1",
"redux": "4.0.1",
"redux-immutable": "4.0.0",
"redux-saga": "0.16.2",
"reselect": "4.0.0",
"sanitize.css": "4.1.0",
"styled-components": "4.0.2",
"warning": "4.0.2"
},
"devDependencies": {
"@babel/cli": "7.1.2",
"@babel/core": "7.1.2",
"@babel/plugin-proposal-class-properties": "7.1.0",
"@babel/plugin-syntax-dynamic-import": "7.0.0",
"@babel/plugin-transform-modules-commonjs": "7.1.0",
"@babel/plugin-transform-react-constant-elements": "7.0.0",
"@babel/plugin-transform-react-inline-elements": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "7.0.0",
"@babel/register": "7.0.0",
"add-asset-html-webpack-plugin": "3.1.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.4",
"babel-plugin-dynamic-import-node": "2.2.0",
"babel-plugin-import": "^1.11.0",
"babel-plugin-lodash": "3.3.4",
"babel-plugin-react-intl": "3.0.1",
"babel-plugin-react-transform": "3.0.0",
"babel-plugin-styled-components": "1.8.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.19",
"circular-dependency-plugin": "5.0.2",
"compare-versions": "3.4.0",
"compression-webpack-plugin": "2.0.0",
"coveralls": "3.0.2",
"css-loader": "1.0.0",
"enzyme": "3.7.0",
"enzyme-adapter-react-16": "1.6.0",
"enzyme-to-json": "3.3.4",
"eslint": "5.7.0",
"eslint-config-airbnb": "17.1.0",
"eslint-config-airbnb-base": "13.1.0",
"eslint-config-prettier": "3.1.0",
"eslint-import-resolver-webpack": "0.10.1",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-prettier": "3.0.0",
"eslint-plugin-react": "7.11.1",
"eslint-plugin-redux-saga": "0.9.0",
"file-loader": "2.0.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"image-webpack-loader": "^4.6.0",
"imports-loader": "0.8.0",
"jest-cli": "^24.5.0",
"jest-styled-components": "6.2.2",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lint-staged": "7.3.0",
"ngrok": "3.1.0",
"node-plop": "0.16.0",
"null-loader": "0.1.1",
"offline-plugin": "5.0.5",
"plop": "2.1.0",
"pre-commit": "1.2.2",
"prettier": "1.14.3",
"react-app-polyfill": "0.1.3",
"react-test-renderer": "16.6.0",
"rimraf": "2.6.2",
"shelljs": "0.8.2",
"style-loader": "0.23.1",
"stylelint": "^9.10.1",
"stylelint-config-recommended": "2.1.0",
"stylelint-config-styled-components": "0.1.1",
"stylelint-processor-styled-components": "1.5.0",
"svg-url-loader": "2.3.2",
"terser-webpack-plugin": "1.1.0",
"url-loader": "1.1.2",
"webpack": "4.23.1",
"webpack-cli": "3.1.2",
"webpack-dev-middleware": "3.4.0",
"webpack-hot-middleware": "2.24.3 ",
"webpack-pwa-manifest": "3.7.1",
"whatwg-fetch": "3.0.0"
}
}
您的代码大体上看起来是正确的。但正如我所见,您使用了 convertToRaw
两次。
const contentState = editorState.getCurrentContent();
const rawContent = convertToRaw(contentState); // <== convert to raw first time
window.localStorage.setItem(
"rawContent",
JSON.stringify(convertToRaw(rawContent)) // <== convert to raw again
);
尝试将 JSON.stringify(convertToRaw(rawContent))
重写为 JSON.stringify(rawContent)
,我认为它应该可以解决您的问题。
如果这没有帮助,您可以查看此 jsFiddle,它显示了 Draft.js 如何与本地存储一起工作的常见模式 - https://jsfiddle.net/x2gsp6ju/4/
在此演示中,您可以看到简单的编辑器组件,当您单击SAVE RAW CONTENT TO LOCAL STORAGE
时,我们将当前编辑器内容作为字符串保存到本地存储。我们为此使用 convertToRaw
和 JSON.stringify
:
saveRaw = () => {
var contentRaw = convertToRaw(this.state.editorState.getCurrentContent());
localStorage.setItem('draftRaw', JSON.stringify(contentRaw));
}
如果之后您重新加载页面,您的编辑器将使用您保存的内容和样式进行初始化。因为在 constructor
中,我们读取了适当的本地存储 属性,并使用 JSON.parse
、convertFromRaw
和 createWithContent
方法使用先前存储的内容初始化编辑器。
constructor(props) {
super(props);
let initialEditorState = null;
const storeRaw = localStorage.getItem('draftRaw');
if (storeRaw) {
const rawContentFromStore = convertFromRaw(JSON.parse(storeRaw));
initialEditorState = EditorState.createWithContent(rawContentFromStore);
} else {
initialEditorState = EditorState.createEmpty();
}
this.state = {
editorState: initialEditorState
};
}
我在从 localStorage 读取 Draft.js 原始内容时遇到问题。
我想使用以前存储的 rawContent 作为我的 initialState
减速器。
我认为 convertFromRaw
功能是我的问题。
我默默地暗恋(不登录到控制台),我不知道如何解决这个问题。
我坚持 Draft.js localStorage 中的原始内容:
const contentState = editorState.getCurrentContent();
const rawContent = convertToRaw(contentState);
window.localStorage.setItem(
"rawContent",
JSON.stringify(convertToRaw(rawContent))
);
然后当我试图恢复它时,我遇到了我的问题。
我认为 convertFromRaw
.
const rawContent = window.localStorage.getItem("rawContent");
if (rawContent) {
this.state.editorState = EditorState.createWithContent(
convertFromRaw(JSON.parse(rawContent))
);
} else {
this.state.editorState = EditorState.createEmpty();
}
我的临时解决方案是使用第三方转换器。
在我的例子中,我使用了 stateToMarkdown / stateFromMarkdown
来自 draft-js-export-markdown / draft-js-import-markdown
我的package.json
{
"name": "react-boilerplate",
"version": "3.7.0",
"description": "A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices",
"repository": {
"type": "git",
"url": "git://github.com/react-boilerplate/react-boilerplate.git"
},
"engines": {
"npm": ">=5",
"node": ">=8.10.0"
},
"author": "Max Stoiber",
"license": "MIT",
"scripts": {
"analyze:clean": "rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"analyze": "node ./internals/scripts/analyze.js",
"extract-intl": "node ./internals/scripts/extract-intl.js",
"npmcheckversion": "node ./internals/scripts/npmcheckversion.js",
"preinstall": "npm run npmcheckversion",
"prebuild": "npm run build:clean",
"build": "cross-env NODE_ENV=production webpack --config internals/webpack/webpack.prod.babel.js --color -p --progress --hide-modules --display-optimization-bailout",
"build:clean": "rimraf ./build",
"start": "cross-env NODE_ENV=development node server",
"start:tunnel": "cross-env NODE_ENV=development ENABLE_TUNNEL=true node server",
"start:production": "npm run test && npm run build && npm run start:prod",
"start:prod": "cross-env NODE_ENV=production node server",
"presetup": "npm i chalk shelljs",
"setup": "node ./internals/scripts/setup.js",
"clean": "shjs ./internals/scripts/clean.js",
"clean:all": "npm run analyze:clean && npm run test:clean && npm run build:clean",
"generate": "plop --plopfile internals/generators/index.js",
"lint": "npm run lint:js",
"lint:css": "stylelint './app/**/*.js'",
"lint:eslint": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts",
"lint:eslint:fix": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts --fix",
"lint:js": "npm run lint:eslint -- . ",
"lint:staged": "lint-staged",
"pretest": "npm run test:clean && npm run lint",
"test:clean": "rimraf ./coverage",
"test": "cross-env NODE_ENV=test jest --coverage",
"test:watch": "cross-env NODE_ENV=test jest --watchAll",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"prettify": "prettier --write"
},
"jest": {
"collectCoverageFrom": [
"app/**/*.{js,jsx}",
"!app/**/*.test.{js,jsx}",
"!app/app.js",
"!app/global-styles.js",
"!app/*/*/Loadable.{js,jsx}"
],
"coverageThreshold": {
"global": {
"statements": 50,
"branches": 40,
"functions": 50,
"lines": 50
}
},
"moduleDirectories": [
"node_modules",
"app"
],
"moduleNameMapper": {
".*\.(css|less|styl|scss|sass)$": "<rootDir>/internals/mocks/cssModule.js",
".*\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/image.js"
},
"setupTestFrameworkScriptFile": "<rootDir>/internals/testing/test-bundler.js",
"testRegex": "tests/.*\.test\.js$"
},
"lint-staged": {
"*.js": [
"npm run lint:eslint:fix",
"git add --force"
],
"*.json": [
"prettier --write",
"git add --force"
]
},
"pre-commit": "lint:staged",
"resolutions": {
"babel-core": "7.0.0-bridge.0"
},
"dependencies": {
"@babel/polyfill": "7.0.0",
"antd": "^3.13.1",
"axios": "^0.18.0",
"chalk": "2.4.1",
"compression": "1.7.3",
"connected-react-router": "4.5.0",
"cross-env": "5.2.0",
"draft-js": "^0.10.5",
"draft-js-export-html": "^1.3.3",
"draft-js-export-markdown": "^1.3.3",
"draft-js-import-html": "^1.3.3",
"draft-js-import-markdown": "^1.3.3",
"express": "4.16.4",
"fontfaceobserver": "2.0.13",
"history": "4.7.2",
"hoist-non-react-statics": "3.0.1",
"immutable": "3.8.2",
"intl": "1.2.5",
"invariant": "2.2.4",
"ip": "1.1.5",
"loadable-components": "2.2.3",
"lodash": "4.17.11",
"minimist": "1.2.0",
"prop-types": "15.6.2",
"react": "16.6.0",
"react-dom": "16.6.0",
"react-draft-wysiwyg": "^1.13.2",
"react-flexview": "^4.0.3",
"react-helmet": "5.2.0",
"react-intl": "2.7.2",
"react-logger-lib": "^1.0.5",
"react-rbac-guard": "0.0.3",
"react-redux": "5.0.7",
"react-router-dom": "4.3.1",
"redux": "4.0.1",
"redux-immutable": "4.0.0",
"redux-saga": "0.16.2",
"reselect": "4.0.0",
"sanitize.css": "4.1.0",
"styled-components": "4.0.2",
"warning": "4.0.2"
},
"devDependencies": {
"@babel/cli": "7.1.2",
"@babel/core": "7.1.2",
"@babel/plugin-proposal-class-properties": "7.1.0",
"@babel/plugin-syntax-dynamic-import": "7.0.0",
"@babel/plugin-transform-modules-commonjs": "7.1.0",
"@babel/plugin-transform-react-constant-elements": "7.0.0",
"@babel/plugin-transform-react-inline-elements": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "7.0.0",
"@babel/register": "7.0.0",
"add-asset-html-webpack-plugin": "3.1.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.4",
"babel-plugin-dynamic-import-node": "2.2.0",
"babel-plugin-import": "^1.11.0",
"babel-plugin-lodash": "3.3.4",
"babel-plugin-react-intl": "3.0.1",
"babel-plugin-react-transform": "3.0.0",
"babel-plugin-styled-components": "1.8.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.19",
"circular-dependency-plugin": "5.0.2",
"compare-versions": "3.4.0",
"compression-webpack-plugin": "2.0.0",
"coveralls": "3.0.2",
"css-loader": "1.0.0",
"enzyme": "3.7.0",
"enzyme-adapter-react-16": "1.6.0",
"enzyme-to-json": "3.3.4",
"eslint": "5.7.0",
"eslint-config-airbnb": "17.1.0",
"eslint-config-airbnb-base": "13.1.0",
"eslint-config-prettier": "3.1.0",
"eslint-import-resolver-webpack": "0.10.1",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-prettier": "3.0.0",
"eslint-plugin-react": "7.11.1",
"eslint-plugin-redux-saga": "0.9.0",
"file-loader": "2.0.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"image-webpack-loader": "^4.6.0",
"imports-loader": "0.8.0",
"jest-cli": "^24.5.0",
"jest-styled-components": "6.2.2",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lint-staged": "7.3.0",
"ngrok": "3.1.0",
"node-plop": "0.16.0",
"null-loader": "0.1.1",
"offline-plugin": "5.0.5",
"plop": "2.1.0",
"pre-commit": "1.2.2",
"prettier": "1.14.3",
"react-app-polyfill": "0.1.3",
"react-test-renderer": "16.6.0",
"rimraf": "2.6.2",
"shelljs": "0.8.2",
"style-loader": "0.23.1",
"stylelint": "^9.10.1",
"stylelint-config-recommended": "2.1.0",
"stylelint-config-styled-components": "0.1.1",
"stylelint-processor-styled-components": "1.5.0",
"svg-url-loader": "2.3.2",
"terser-webpack-plugin": "1.1.0",
"url-loader": "1.1.2",
"webpack": "4.23.1",
"webpack-cli": "3.1.2",
"webpack-dev-middleware": "3.4.0",
"webpack-hot-middleware": "2.24.3 ",
"webpack-pwa-manifest": "3.7.1",
"whatwg-fetch": "3.0.0"
}
}
您的代码大体上看起来是正确的。但正如我所见,您使用了 convertToRaw
两次。
const contentState = editorState.getCurrentContent();
const rawContent = convertToRaw(contentState); // <== convert to raw first time
window.localStorage.setItem(
"rawContent",
JSON.stringify(convertToRaw(rawContent)) // <== convert to raw again
);
尝试将 JSON.stringify(convertToRaw(rawContent))
重写为 JSON.stringify(rawContent)
,我认为它应该可以解决您的问题。
如果这没有帮助,您可以查看此 jsFiddle,它显示了 Draft.js 如何与本地存储一起工作的常见模式 - https://jsfiddle.net/x2gsp6ju/4/
在此演示中,您可以看到简单的编辑器组件,当您单击SAVE RAW CONTENT TO LOCAL STORAGE
时,我们将当前编辑器内容作为字符串保存到本地存储。我们为此使用 convertToRaw
和 JSON.stringify
:
saveRaw = () => {
var contentRaw = convertToRaw(this.state.editorState.getCurrentContent());
localStorage.setItem('draftRaw', JSON.stringify(contentRaw));
}
如果之后您重新加载页面,您的编辑器将使用您保存的内容和样式进行初始化。因为在 constructor
中,我们读取了适当的本地存储 属性,并使用 JSON.parse
、convertFromRaw
和 createWithContent
方法使用先前存储的内容初始化编辑器。
constructor(props) {
super(props);
let initialEditorState = null;
const storeRaw = localStorage.getItem('draftRaw');
if (storeRaw) {
const rawContentFromStore = convertFromRaw(JSON.parse(storeRaw));
initialEditorState = EditorState.createWithContent(rawContentFromStore);
} else {
initialEditorState = EditorState.createEmpty();
}
this.state = {
editorState: initialEditorState
};
}