preface
As a front-end developer, it is an essential skill to master vUE/React/Angular and other frameworks. As we all know, MVVM frameworks such as VUE or React advocate component-based development, which on the one hand can improve the reusability and scalability of components, on the other hand, it also brings the flexibility and maintainability of project development, which is convenient for many people Develop collaboration. The next article will show you how to develop a custom JSON editor component using React. We use jsonEditor, a third-party library, to learn how to encapsulate your components (not limited to React,vue, similar principles) by implementing an online JSON editor.
You will learn:
- Basic idea of react component encapsulation
- Introduction to SOLID (Object-oriented Design) principles
- Jsoneditor usage
- Use PropTypes for component type checking
Design ideas
Before introducing the idea of component design, it is worth introducing the well-known SOLID principle.
SOLID (single function, open closed principle, Richter substitution, Interface isolation, and Dependency Reversal) are the five basic principles of object-oriented programming and object-oriented design proposed by Robert C. Martin. Using these principles, programmers can more easily and efficiently develop a system that is maintainable and extensible. SOLID is typically used in test-driven development and is an important part of the basic principles of agile and adaptive software development.
-
Single function principle: states that each class should have a single function, and that function should be fully encapsulated by the class. All its services should be closely aligned with this functionality.
-
O Open closed principle: states that “objects in software (classes, modules, functions, etc.) should be open for extension but closed for modification.” This means that an entity is allowed to change its behavior without changing its source code. Code that follows this principle does not need to change as it expands.
-
L Richter’s substitution principle: a derived class (subclass) object can replace its base class (superclass) object in a program, which is a special definition of a subtype.
-
I Interface isolation rule: specifies that an application or object should not depend on methods it does not use. The interface isolation principle (ISP) splits very large, bloated interfaces into smaller, more concrete ones, so that applications or objects only need to know the methods they are interested in. This scaled-down interface is also known as the role interface. The goal of the Interface Isolation principle (ISP) is to decouple the system so that it is easy to refactor, change, and redeploy. The interface isolation principle is one of the five principles of object Oriented design (OOD) in SOLID, similar to the high cohesion in GRASP.
-
D Dependency reversal principle: refers to a specific form of decoupling, so that high-level modules do not depend on the implementation details of low-level modules, and the dependency relationship is reversed (reversed), so that low-level modules depend on the requirement abstraction of high-level modules.
Keeping these five principles in mind will help us develop better components. Let’s take a look at how the JSON editor is designed.
First of all, using the basic style and API of JsonEditor rendering, we can implement a basic usable JSON editor. Then, we can use the exposed JSON and onChange property to two-way data binding, and monitor exceptions or input errors with onError. Using themeBgColor to change the default theme color, we can use these interfaces to fully understand how a component is running.
The body of the
Then we will formally begin our text. Since the components in this article are implemented based on React, the basic pattern applies to Vue and Angular. The key is to understand the lifecycle of the different frameworks.
Before learning how to implement the JSON editor component, it is important to look at the usage and API of jsonEditor, a third-party component.
The use of jsoneditor
- The installation
We first run NPM install to install our components
npm install jsoneditor
Copy the code
Next, manually import the style file
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
Copy the code
This way, we can use its API:
<div id="jsoneditor" style="width: 400px; height: 400px;"></div>
<script>
// Create an editor
var container = document.getElementById("jsoneditor");
var editor = new JSONEditor(container);
// Set the JSON data
function setJSON () {
var json = {
"Array": [1.2.3]."Boolean": true."Null": null."Number": 123."Object": {"a": "b"."c": "d"},
"String": "Hello World"
};
editor.set(json);
}
// Get the JSON data
function getJSON() {
var json = editor.get();
alert(JSON.stringify(json, null.2));
}
</script>
Copy the code
So you might see something like this:
Combine react for secondary encapsulation
Based on the above discussion, it is easy to encapsulate the editor as a React component, we simply initialize the instance in the componentDidMount lifecycle. React code might look like this:
import React, { PureComponent } from 'react'
import JSONEditor from 'jsoneditor'
import 'jsoneditor/dist/jsoneditor.css'
class JsonEditor extends PureComponent {
initJsonEditor = (a)= > {
const options = {
mode: 'code'.history: true.onChange: this.onChange,
onValidationError: this.onError
};
this.jsoneditor = new JSONEditor(this.container, options)
this.jsoneditor.set(this.props.value)
}
componentDidMount () {
this.initJsonEditor()
}
componentWillUnmount () {
if (this.jsoneditor) {
this.jsoneditor.destroy()
}
}
render() {
return <div className="jsoneditor-react-container" ref={elem= > this.container = elem} />
}
}
export default JsonEditor
Copy the code
For options, we can refer to the JsonEditor API documentation, which is very detailed. With the above code, we can implement a basic REACT version of the JSON editor component. Let’s follow the design roadmap to implement a real-time previewable JSON editor component.
- Implement preview and edit views
This is easy to implement. We only need to instantiate 2 editor instances, one for preview and one for editing.
import React, { PureComponent } from 'react'
import JSONEditor from 'jsoneditor'
import 'jsoneditor/dist/jsoneditor.css'
class JsonEditor extends PureComponent {
onChange = (a)= > {
let value = this.jsoneditor.get()
this.viewJsoneditor.set(value)
}
initJsonEditor = (a)= > {
const options = {
mode: 'code'.history: true
};
this.jsoneditor = new JSONEditor(this.container, options)
this.jsoneditor.set(this.props.value)
}
initViewJsonEditor = (a)= > {
const options = {
mode: 'view'
};
this.viewJsoneditor = new JSONEditor(this.viewContainer, options)
this.viewJsoneditor.set(this.props.value)
}
componentDidMount () {
this.initJsonEditor()
this.initViewJsonEditor()
}
componentDidUpdate() {
if(this.jsoneditor) {
this.jsoneditor.update(this.props.value)
this.viewJsoneditor.update(this.props.value)
}
}
render() {
return( <div className="jsonEditWrap"> <div className="jsoneditor-react-container" ref={elem => this.container = elem} /> <div className="jsoneditor-react-container" ref={elem => this.viewContainer = elem} /> </div> ); } } export default JsonEditorCopy the code
In this way, we can implement a preliminary preview editor in real time. It might look like this:
- Expose properties and methods to support the needs of different scenarios
import React, { PureComponent } from 'react'
import JSONEditor from 'jsoneditor'
import 'jsoneditor/dist/jsoneditor.css'
class JsonEditor extends PureComponent {
// Listen for changes in input values
onChange = (a)= > {
let value = this.jsoneditor.get()
this.props.onChange && this.props.onChange(value)
this.viewJsoneditor.set(value)
}
// Expose json data from the fetching editor
getJson = (a)= > {
this.props.getJson && this.props.getJson(this.jsoneditor.get())
}
// Submit error information
onError = (errArr) = > {
this.props.onError && this.props.onError(errArr)
}
initJsonEditor = (a)= > {
const options = {
mode: 'code'.history: true.onChange: this.onChange,
onValidationError: this.onError
};
this.jsoneditor = new JSONEditor(this.container, options)
this.jsoneditor.set(this.props.value)
}
initViewJsonEditor = (a)= > {
const options = {
mode: 'view'
};
this.viewJsoneditor = new JSONEditor(this.viewContainer, options)
this.viewJsoneditor.set(this.props.value)
}
componentDidMount () {
this.initJsonEditor()
this.initViewJsonEditor()
// Set the theme color
this.container.querySelector('.jsoneditor-menu').style.backgroundColor = this.props.themeBgColor
this.container.querySelector('.jsoneditor').style.border = `thin solid The ${this.props.themeBgColor}`
this.viewContainer.querySelector('.jsoneditor-menu').style.backgroundColor = this.props.themeBgColor
this.viewContainer.querySelector('.jsoneditor').style.border = `thin solid The ${this.props.themeBgColor}`
}
componentDidUpdate() {
if(this.jsoneditor) {
this.jsoneditor.update(this.props.json)
this.viewJsoneditor.update(this.props.json)
}
}
render() {
return( <div className="jsonEditWrap"> <div className="jsoneditor-react-container" ref={elem => this.container = elem} /> <div className="jsoneditor-react-container" ref={elem => this.viewContainer = elem} /> </div> ); } } export default JsonEditorCopy the code
With the above process, we have completed the majority of the work. The remaining details and optimizations, such as how to uninstall the instance when the component is unloaded, type detection of the component, etc., we continue to complete the above issues.
- PropTypes are used for type detection and to clear instances when components are unloaded When installing React, PropTypes will be automatically installed for us. For details, please refer to the PropTypes document on the official website. Secondly, we will clear the editor instances in the React componentWillUnmount life cycle to free up memory. The complete code is as follows:
import React, { PureComponent } from 'react'
import JSONEditor from 'jsoneditor'
import PropTypes from 'prop-types'
import 'jsoneditor/dist/jsoneditor.css'
/** * JsonEditor * @param {object} JSON for binding json data * @param {func} onChange callback * @param {func} getJson @param {func} onError provides a callback for the external json format error * @param {string} themeBgColor changes the theme color for external exposure */
class JsonEditor extends PureComponent {
onChange = (a)= > {
let value = this.jsoneditor.get()
this.props.onChange && this.props.onChange(value)
this.viewJsoneditor.set(value)
}
getJson = (a)= > {
this.props.getJson && this.props.getJson(this.jsoneditor.get())
}
onError = (errArr) = > {
this.props.onError && this.props.onError(errArr)
}
initJsonEditor = (a)= > {
const options = {
mode: 'code'.history: true.onChange: this.onChange,
onValidationError: this.onError
};
this.jsoneditor = new JSONEditor(this.container, options)
this.jsoneditor.set(this.props.value)
}
initViewJsonEditor = (a)= > {
const options = {
mode: 'view'
};
this.viewJsoneditor = new JSONEditor(this.viewContainer, options)
this.viewJsoneditor.set(this.props.value)
}
componentDidMount () {
this.initJsonEditor()
this.initViewJsonEditor()
// Set the theme color
this.container.querySelector('.jsoneditor-menu').style.backgroundColor = this.props.themeBgColor
this.container.querySelector('.jsoneditor').style.border = `thin solid The ${this.props.themeBgColor}`
this.viewContainer.querySelector('.jsoneditor-menu').style.backgroundColor = this.props.themeBgColor
this.viewContainer.querySelector('.jsoneditor').style.border = `thin solid The ${this.props.themeBgColor}`
}
componentWillUnmount () {
if (this.jsoneditor) {
this.jsoneditor.destroy()
this.viewJsoneditor.destroy()
}
}
componentDidUpdate() {
if(this.jsoneditor) {
this.jsoneditor.update(this.props.json)
this.viewJsoneditor.update(this.props.json)
}
}
render() {
return( <div className="jsonEditWrap"> <div className="jsoneditor-react-container" ref={elem => this.container = elem} /> <div className="jsoneditor-react-container" ref={elem => this.viewContainer = elem} /> </div> ); } } JsonEditor.propTypes = { json: PropTypes.object, onChange: PropTypes.func, getJson: PropTypes.func, onError: PropTypes.func, themeBgColor: PropTypes.string } export default JsonEditorCopy the code
Since components strictly adhere to the open closed principle, we can provide more customized functionality in our JSON editor to meet the needs of different projects. For a robust discussion of component development, in addition to propTypes, development can be based on typescript, which is suitable for teams developing component libraries or for traceability and error checking of complex project components. The final result is as follows:
I have published the implemented components to NPM. If you are interested, you can directly use NPM after installation. The method is as follows:
npm i @alex_xu/xui
/ / import xui
import {
Button,
Skeleton,
Empty,
Progress,
Tag,
Switch,
Drawer,
Badge,
Alert
} from '@alex_xu/xui'
Copy the code
This component library can be imported on demand. We only need to configure babel-plugin-import in the project. The specific configuration is as follows:
// .babelrc
"plugins": [["import", { "libraryName": "@alex_xu/xui"."style": true}]]Copy the code
The NPM library screenshot is as follows:
The last
If you want to learn more about H5 games, Webpack, node, gulp, CSS3, javascript, nodeJS, Canvas data visualization and other front-end knowledge and practical, welcome to join us in the public account “Interesting Talk front-end” to learn and discuss, and jointly explore the boundary of the front-end.
More recommended
- In 2019, take a look at some of my top questions and advice for job seekers
- “Front-end combat summary” the use of pure CSS website skin and focus diagram switch animation
- “Front-end combat summary” using CSS3 to achieve cool 3D rotation perspective
- Add a loading progress bar to your site using pace. Js
- The Application of design Pattern of “Summary of Front End Actual Combat” — Memorandum Pattern
- “Front End Combat Summary” using postMessage to achieve pluggable cross-domain chatbot
- “Front-end combat summary” of the variable promotion, function declaration promotion and variable scope detailed explanation
- “Front-end combat summary” how to change the URL without refreshing the page
- A picture shows you how to play vue-Cli3 quickly
- Vue Advanced Advanced series – Play with Vue and vuex in typescript
- Implementing a CMS full stack project from 0 to 1 based on nodeJS (Part 1)
- Implementing a CMS full stack project from 0 to 1 based on nodeJS (middle)
- Implement a CMS full stack project from 0 to 1 based on nodeJS (Part 2)
- Write a mock data server using nodeJS in 5 minutes
- With CSS3 to achieve stunning interviewers background that background animation (advanced source)
- Teach you to use 200 lines of code to write a love bean spell H5 small game (with source code)
- Cartesian product is implemented and applied in javascript