data flow
The change of data is usually triggered by user interaction behavior or browser behavior (such as routing jump, etc.). When such behavior changes the data, dispatch
an action can be initiated. If it is a synchronous behavior, it will be directly Reducers
changed State
. Asynchronous behavior (side effects) will be triggered first Effects
and then flow to the Reducers
final change State
, so in dva, the data flow is very clear and concise, and the idea is basically consistent with the open source community (also from the open source community).
Models
State
type State = any
State represents the state data of the Model, which is usually represented as a javascript object (of course it can be any value); when operating, it must be treated as immutable data every time to ensure that it is a new object every time, no Reference relationship, so as to ensure the independence of State, easy to test and track changes.
In dva you can _store
see the top state data through the dva's instance properties, but usually you will rarely use:
const app = dva(); console. log( app. _store); // state data at the top
Action
type AsyncAction = any
Action is a plain javascript object, it is the only way to change State. Whether it is data obtained from UI events, network callbacks, or data sources such as WebSockets, an action will eventually be called through the dispatch function to change the corresponding data. Action must have type
attributes to indicate specific behaviors, and other fields can be customized. If you want to initiate an action, you need to use a dispatch
function; it should be noted that dispatch
after the component is connected to Models, it is passed in through props.
dispatch({
type: 'add',
});
dispatch function
type dispatch = (a: Action) => Action
dispatching function is a function used to trigger action, action is the only way to change state, but it only describes a behavior, and dispatch can be seen as a way to trigger this behavior, while reducer describes how to change data.
In dva, the components of the connect Model can access the dispatch through props, and can call the Reducer or Effects in the Model. Common forms are:
dispatch({
type : 'user/add ', // if called outside the model, you need to add namespace payload : {}, // the information to be passed});
Reducer
type Reducer<S, A> = (state: S, action: A) => S
The Reducer (also known as reducing function) function accepts two parameters: the result of the previous accumulated operation and the current value to be accumulated, and returns a new accumulated result. This function merges a collection into a single value.
The concept of Reducer comes from functional programming, and there are reduce APIs in many languages. As in javascript:
[{x:1},{y:2},{z:3}].reduce(function(prev, next){ return Object.assign(prev, next); }) //return {x:1, y:2, z:3}
In dva, the aggregated result of reducers is the state object of the current model. The new value (that is, the new state) is obtained by operating the value passed in the actions with the value in the current reducers. Note that Reducers must be pure functions , so the same input must result in the same output, and they should not produce any side effects. Moreover, immutable data should be used for each calculation . The simple understanding of this feature is that each operation returns a new data (independent, pure), so functions such as hot reloading and time travel can be used.
Effect
Effects are called side effects, and in our application, the most common ones are asynchronous operations. It comes from the concept of functional programming, and it is called side effects because it makes our function impure, the same input does not necessarily get the same output.
In order to control the operation of side effects, dva introduces redux-sagas at the bottom for asynchronous process control. Because of the concept of generator , it converts asynchronous to synchronous writing, thereby turning effects into pure functions. As for why we are so obsessed with pure functions, if you want to know more, you can read the Mostly adequate guide to FP , or its Chinese translation of the JS Functional Programming Guide .
Subscription
Subscriptions are a way to get data from a source, it comes from elm.
Subscription semantics are subscriptions, which are used to subscribe to a data source and then dispatch the required actions according to conditions. The data source can be the current time, the server's websocket connection, keyboard input, geolocation changes, history routing changes, and so on.
import key from 'keymaster'; ... app.model({ namespace: 'count', subscriptions: { keyEvent(dispatch) { key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) }); }, } });
Router
The routing here usually refers to front-end routing. Since our application is usually a single-page application now, we need front-end code to control the routing logic. Through the History API provided by the browser, we can monitor changes in the browser url to control routing-related operations. .
The dva instance provides the router method to control routing, using react-router .
import { Router, Route } from 'dva/router'; app.router(({history}) => <Router history={history}> <Route path="/" component={HomePage} /> </Router> );
Route Components
In the component design method , we mentioned Container Components, in dva we usually constrain it to Route Components, because in dva we usually design Container Components in terms of page dimensions.
Therefore, in dva, the components that usually need to connect Model are Route Components, which are organized in a /routes/
directory, and the /components/
directory is a pure component (Presentational Components).
References
- redux docs
- redux docs in Chinese
- Mostly adequate guide to FP
- JS Functional Programming Guide
- choo docs
- elm
Original address: https://github.com/dvajs/dva/blob/master/docs/Concepts_zh-CN.md