Recently, we made an internal application similar to IDE, based on Electron and DVA. Since we only focused on developer tools related to Node before, we didn’t have much contact with React and other content, so it was a little difficult and exciting during this period of time. The suffering came from the non-comfort zone. The excitement comes from finding more possibilities for developer tools based on DVA + Electron.

Sorrycc student sorrycc organized the IDE project into dva-boilerplate-electron.

First understanding of DVA is the first article of this summary. In the second article, I will record related precipitation in electron.

Back to how to play React, Dva, Electron in a few days.


React Basics

What is React O.O?

React’s core purpose is to create UI components, which means it’s layer V in the MVC architecture, so React has nothing to do with your technical architecture.

For example, in AngularJS 1.x it extends HTML tags to inject some structural stuff (like Controllers, Services), so AngularJS 1.x is invading your entire technology architecture, In some ways these abstractions do solve some business problems, but as a result the tower lacks flexibility.

React’s library, which only focuses on Components, gives developers a great deal of flexibility because I’m not tied to one technical architecture.

What happens to Components in each lifecycle?

the-component-lifecycle

Summing up,

At the top, the React Component lifecycle falls into three phases:

  • Initialization
  • State/ props Updates, state/ Property Updates
  • Destruction of Destruction

These three categories correspond to the React abstract methods. These methods are component-specific hooks that are executed once or more during a component’s lifetime. Knowing when these hooks are called can help you write components better.

Such as:

ComponentWillMount: Executes before component render and always executes only once.

ComponentDidMount: componentDidMount is executed immediately after the component is loaded, and the corresponding node is generated in the DOM tree at this time, so we use this.getDomNode () to get the corresponding node.

Please refer to the documentation for details.

Several ways to create a component

  • The React of writing
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom'

var SayHi = React.createClass({
  getInitialState(){
    return {};
  },
  getDefaultProps(){
      return { from: 'pigcan' };
  }
  propTypes:{
    name: PropTypes.string.isRequired,
  },
  render(){
    var name=this.props.name;
    return(
      

{from} says: hello {name}!

); } }) ReactDOM.render( , document.getElementById('demo') )Copy the code

  • ES6 writing
import React, { Component, PropTypes } from 'react'; import { Popover, Icon } from 'antd'; Class PreviewQRCodeBar extends Component {// The way a Component is declared constructor(props) {// The work of initialization is put into the super(props); // In es6 if there is a parent class, there must be a call to super to initialize the parent information this.state = {// The initial state is set to visible: false,}; } // Hide () {this.setState({visible: false,}); } handleVisibleChange(visible) { this.setState({ visible }); } render() { const { dataurl } = this.props; Return (} the trigger = "click" visible = {this. State. The visible} onVisibleChange = {this. HandleVisibleChange. Bind (this)} / / pass .bind(this) to bind >); }} / / in the react in writing, directly through propTypes {key: value} to agreed PreviewQRCodeBar. PropTypes = {dataurl: PropTypes.string.isRequired, }; // In the REACT class declaration, the method getDefaultProps(){} is used to set the props property PreviewQRCodeBar.defaults = { // obj } export default PreviewQRCodeBar;Copy the code

  • Stateless writing
import React, { PropTypes } from 'react'; // No state, pure function const PreviewDevToolWebview = ({remoteUrl}) => PreviewDevToolWebview.proptype = { remoteUrl: PropTypes.string.isRequired, }; export default PreviewDevToolWebview; // This type of component does not support the ref attribute, there are no related times and methods for the component lifecycle, only support propTypes // this type of component simply renders dataCopy the code

If you want to learn more about the basics

  • dva-knowledgemap
  • es6

What the hell is Flux

In short, Flux is an architectural idea, which, like MVC, is used to solve the problem of software structure. As mentioned above, React only involves the UI layer, so it must have a matching application architecture when building large-scale applications. In the React community, Flux architecture is widely used to build applications.

The most significant feature of Flux is its one-way data flow. The core purpose of Flux is to avoid data pollution in multi-component interaction.

In flux mode, the Store layer is the power center of all data, and any data change needs to happen in the Store. The data change in the Store layer will be broadcast to the View that subscribes to the event in the form of events, and then the View will update itself according to the new data state received. Any Action that you want to change the Store layer data needs to be called, and these Actions are centrally scheduled by the Dispatcher. When using Actions, you need to ensure that each Action corresponds to a data update and only one Action is triggered at a time.

To tell you my personal feeling, in the old MVC architecture, the data of a Model may be shared by multiple views, and each View usually has its own Controller layer to represent the Model and View. Then a significant problem appears. Any Controller can cause data updates to the Model. In reality, our applications usually have more complex UI layers, so if used incorrectly, our data flow will be chaotic, and it will become more and more difficult to debug because it is difficult to determine the exact location of data changes.

Data flow in DVA

How do you understand that?

In Web applications, data changes usually occur in user interaction behavior or browser behavior (such as route jump, etc.). When such behavior changes data, an action can be initiated through Dispatch. In case of synchronous behavior, State can be directly changed through Reducers. If the behavior is asynchronous, Effects will be triggered first, then flow to Reducers and finally change State. Therefore, in DVA, data flow is very clear and concise, and the idea is basically consistent with the open source community.


Basic concepts of DVA

In short, DVA is a lightweight package based on existing application architectures (Redux + React-Router + Redux-Saga, etc.)

What is the dva

What are the basic concepts of DVA?

The following is excerpted from Dva Concepts

dva – Model

State

State represents the State data of a Model, which is typically represented as immutable data, a javascript object.

Action

Action is a plain javascript object that is the only way to change State. Whether the data is retrieved from a UI event, a network callback, or a data source such as WebSocket, an action is eventually called through the Dispatch function to change the corresponding data. ** Note that dispatches are passed in via props after the component Connect Models. **

Dispatch ({type: 'user/add', // Add namespace payload: {}, // Send information});Copy the code

The object inside the above called function is an action.

The dispatch function

Action is the only way to change State, but it only describes one behavior. Dipatch can be seen as the way to trigger this behavior, while Reducer describes how to change data.

dva – Reducer

In DVA, the result of the reducers aggregation is the state object of the current model. The new value (i.e., the new state) is computed with the value in the current reducers from the values passed in the Actions. It is important to note that Reducer must be a pure function.

App.model ({namespace: 'todos', // Namespace state of model: [], // Initializing data reducers of model: Add (state, {payload: payload) {// Add (state, {payload: todo }) { return state.concat(todo); ,}}};Copy the code

dva – Effect

Effect is called side Effect. In our application, asynchronous operation is the most common one, and the final flow of Effects is to change State through Reducers.

The core needs to focus on put, call, select.

app.model({ namespace: 'todos', effects: { *addRemote({ payload: todo }, { put, call, select }) { const todos = yield select(state => state.todos); // The state here comes from the global state. The select method provides the ability to obtain the global state. The yield call(addTodo, todo) can be obtained by using state.modelName; // Used to invoke asynchronous logic, support promise. yield put({ type: 'add', payload: todo }); // Trigger action. It should be noted that the reducer or effects called by the action comes from this model, so there is no need to declare a namespace in type. If other methods other than this model need to be triggered, a namespace needs to be declared in type. For example, yield PUT ({type: 'namespace/fuc', payload: XXX}); ,}}});Copy the code

dva – Subscription

Subscriptions is a method of obtaining data from sources, which came from ELM.

The Subscription semantics are subscriptions that are used to subscribe to a data source and then dispatch required actions based on conditions. The data sources can be the current time, the server’s Websocket connection, keyboard input, geolocation changes, history route changes, and so on.

import key from 'keymaster'; . app.model({ namespace: 'count', subscriptions: {{keyEvent (dispatch) key (' ⌘ + up and CTRL + up, () = > {dispatch ({type: 'add'})}); }}});Copy the code

dva – Router

Routing here usually refers to front-end routing. Since our application is now usually a single page application, front-end code is required to control the routing logic. The History API provided by the browser can monitor the browser URL changes to control routing operations.

The DVA instance provides the router method to control routing, using the React-router.

import { Router, Route } from 'dva/router';
app.router(({history}) =>
  
    
  
);Copy the code

See the react to the router

dva – Route Components

In DVA we usually design Container Components in terms of page dimensions.

Therefore, in DVA, normally connect Model Components are Route Components, organized in the /routes/ directory, and/Components/directory are pure Presentational Components.

** Bind data with CONNECT **

Such as:

import { connect } from 'dva'; Function App() {} function mapStateToProps(state, ownProps) {// Function function mapStateToProps(state, ownProps) { Also automatically registers a dispatch method that triggers action return {users: state.users,}; } export default connect(mapStateToProps)(App);Copy the code

And then you have dispatch and Users properties in your App.


Ok, the above are some core concepts in DVA. At first, you may receive a lot of information, but don’t worry, the use of the following business will make you clearer and clearer about the above concepts.

So how do you start a DVA application

// Install dva-cli
$ npm install dva-cli -g

// Create app and start
$ dva new myapp
$ cd myapp
$ npm install
$ npm startCopy the code

Done o.o

Let’s take a look at the DVA project SRC directory structure to try to understand how the overall code is organized

. ├ ─ ─ assets │ └ ─ ─ yay. JPG ├ ─ ─ components │ └ ─ ─ Example, js ├ ─ ─ index. The CSS ├ ─ ─ index. The HTML ├ ─ ─ index. The js ├ ─ ─ models │ └ ─ ─ Example. Js ├ ─ ─ the router. Js ├ ─ ─ routes │ ├ ─ ─ IndexPage. CSS │ └ ─ ─ IndexPage. Js ├ ─ ─ services │ └ ─ ─ example, js ├ ─ ─ tests │ └ ─ ─ Models │ ├ ─ ├ ─ ├ ─ sci-impCopy the code

Assets: We can leave the project assets here. Components: Pure components. In DVA applications, the components directory should be some Logicless components, and the logic part is carried by the corresponding Route-Component. After installing the DVA-CLI tool, we can create a Component by dVA g Component componentName. Index.css: home page style index.html: home page index.js: dVA This directory structure is used to store models. In general, a Model corresponds to a Route-Component, and a Route-Component corresponds to multiple Components, depending on how you split them. I prefer to split them as fine-grained as possible. After installing the DVA-CLI tool, we can create a model by using dVA G Model modelName. The model is automatically registered in index.js. Router.js: route configuration for the page, importing routes to the route-component: If a route-Component exists, after installing the DVA-CLI tool, we can create a Route-Component by using dva g route route-name. The route configuration is automatically updated to route.js. Route-component is a heavy logic area, where all general business logic is processed. Through the connect method, model and Component are linked. Services: global services such as sending asynchronous requests tests: related utils: global class public functions

Dva's five songs

import './index.html'; import './index.css'; import dva from 'dva'; // 1. Initialize const app = dva(); // Plugins - app.use({}); //app. Model (require('./models/example')); // 4. Configure Router app. Router (require('./ Router ')); // 5. Start app.start('#root');Copy the code

Well, the above are the five songs, read the DVA official documents may say that there is a step less

// 4. Connect components and models
const App = connect(mapStateToProps)(Component);Copy the code

The reason is that in real business, our connect behavior is usually set in the Route-Component.


The above.

By the way, remember to register the model in index.js when you manually add a model. Of course, scaffolding is not a problem. XD.