О два
Потому что раньше я использовал react+redux. На этот раз я связался с фреймворком два для простого исследования. В этой статье в основном объясняется разработка общих API-интерфейсов и некоторые навыки использования в среде dva.Если вы хотите просмотреть более подробные API-интерфейсы, обратитесь к официальной документации dva:Официальная демоверсия
Простые шаги установки
1. Сначала установите dva-cli глобально
$ npm install -g dva-cli
2. Затем используйте DVA-CLI для создания нашей папки проекта, где MyDVA - это имя проекта, вы можете делать все, что вы хотите.
$ dva new mydva
3. Войдите в каталог mydva, в зависимости от установки, выполните следующие операции.
$ cd myapp
$ npm start
4. После успешного запуска интерфейс выглядит следующим образом
5. Каталог файлов и анализ
├── mock // mock数据文件夹
├── node_modules // 第三方的依赖
├── public // 存放公共public文件的文件夹
├── src // 最重要的文件夹,编写代码都在这个文件夹下
│ ├── assets // 可以放图片等公共资源
│ ├── components // 就是react中的木偶组件
│ ├── models // dva最重要的文件夹,所有的数据交互及逻辑都写在这里
│ ├── routes // 就是react中的智能组件,不要被文件夹名字误导。
│ ├── services // 放请求借口方法的文件夹
│ ├── utils // 自己的工具方法可以放在这边
│ ├── index.css // 入口文件样式
│ ├── index.ejs // ejs模板引擎
│ ├── index.js // 入口文件
│ └── router.js // 项目的路由文件
├── .eslintrc // bower安装目录的配置
├── .editorconfig // 保证代码在不同编辑器可视化的工具
├── .gitignore // git上传时忽略的文件
├── .roadhogrc.js // 项目的配置文件,配置接口转发,css_module等都在这边。
├── .roadhogrc.mock.js // 项目的配置文件
└── package.json // 当前整一个项目的依赖
Простая демонстрация, ссылкаОфициальная демонстрация расчета
1. Сначала изменитьroute/IndexPage.js
import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css';
class IndexPage extends React.Component {
render() {
const { dispatch } = this.props;
return (
<div className={styles.normal}>
<div className={styles.record}>Highest Record: 1</div>
<div className={styles.current}>2</div>
<div className={styles.button}>
<button onClick={() => {}}>+</button>
</div>
</div>
);
}
}
export default connect()(IndexPage);
2. Далее изменить стильroutes/IndexPage.css
.normal {
width: 200px;
margin: 100px auto;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 0 20px #ccc;
}
.record {
border-bottom: 1px solid #ccc;
padding-bottom: 8px;
color: #ccc;
}
.current {
text-align: center;
font-size: 40px;
padding: 40px 0;
}
.button {
text-align: center;
}
button {
width: 100px;
height: 40px;
background: #aaa;
color: #fff;
}
3. Интерфейс отображается следующим образом
4. Вmodel
иметь дело сstate
, в выводе страницыmodel
серединаstate
(1) Сначала мыindex.js
генерал-лейтенантmodels/example.js
, Откройте аннотацию следующей строки модели.
import './index.css';
import dva from 'dva';
import model from './models/example'
import router from './router'
// 1. Initialize 创建dva实列
const app = dva();
// 2. Plugins 装载插件(可选)
// app.use({});
// 3. Model 注册modal
app.model(model);
// 4. Router 配置路由
app.router(router);
// 5. Start 启动应用
app.start('#root');
(2) Далее мы вводимmodels/example.js
,Будуnamespace
имя измененоcount
,state
объект плюсrecord
а такжеcurrent
Атрибуты
export default {
namespace: 'count',
state: {
record: 0,
current: 0,
},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-lines
},
},
effects: {
*fetch({ payload }, { call, put }) { // eslint-disable-line
yield put({ type: 'save' });
},
},
reducers: {
save(state, action) {
return { ...state, ...action.payload };
},
},
};
(3) Затем мы приходим кroutes/indexpage.js
страница, черезmapStateToProps
связанные с импортомstate
.
import React from "react";
import { connect } from "dva";
import styles from "./IndexPage.css";
class IndexPage extends React.Component {
render() {
const { dispatch, count } = this.props;
return (
<div className={styles.normal}>
<div className={styles.record}>Highest Record: {count.record}</div>
{/* // 将count的record输出 */}
<div className={styles.current}>{count.current}</div>
<div className={styles.button}>
<button
onClick={() => {
}}
>
+
</button>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return { count: state.count };
} // 获取state
export default connect(mapStateToProps)(IndexPage);
(4) Здесь нам нужно объяснить описание внедрения зависимостей React (mapStateToProps
/mapDispatchToProps
)
понадобится
state
узел вводится в компонент, связанный с данными этого представления
function mapStateToProps(state, ownProps) {
return {
loading:state.getIn(['projectPre', 'projectMgr', 'loading']),
data:state.getIn(['APP', 'data']),
...
}
// loading、data都是来自对应的reduce
}
Внедрить события ответа, которые необходимо привязать к компоненту.
function mapDispatchToProps(dispatch){
return {
...bindActionCreators(action, dispatch)
}
}
// mapDispatchToProps()函数的bindActionCreators、action需要引入
// import * as action from '../action';
// import { bindActionCreators } from 'redux';
------------------------------------
------------------------------------
// 多个action 引入
import * as action from '../action';
import * as action2 from '../../../inde/action';
function mapDispatchToProps(dispatch){
return {
...bindActionCreators(action, dispatch)
...bindActionCreators(action2, dispatch)
}
}
------------------------------------
------------------------------------
// 引入一个action里面的多个方法
import { activeOrAbandonedApproval, showSeller, getAddOrderDiscounts } from '../orderInfo/action'
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ activeOrAbandonedApproval, showSeller, getAddOrderDiscounts }, dispatch)
}
}
(5) пройти+
Отправитьaction
,пройти черезreducer
изменить соответствующийstate
export default {
...
reducers: {
add1(state) {
const newCurrent = state.current + 1;
return { ...state,
record: newCurrent > state.record ? newCurrent : state.record,
current: newCurrent,
};
},
minus(state) {
return { ...state, current: state.current - 1 };
},
},
};
(6) Сначала мы находимся вmodels/example.js
, напишите соответствующийreducer
.
export default {
namespace: "count",
state: {
record: 0,
current: 0
},
subscriptions: {
setup({ dispatch, history }) {
// eslint-disable-lines
}
},
effects: {
*fetch({ payload }, { call, put }) {
// eslint-disable-line
yield put({ type: "save" });
}
},
reducers: {
add(state) {
const newCurrent = state.current + 1;
return {
...state,
record: newCurrent > state.record ? newCurrent : state.record,
current: newCurrent
};
},
minus(state) {
return { ...state, current: state.current - 1 };
}
}
};
(7) Шаблон на страницеroutes/IndexPage.js
середина+
При нажатии на номерdispatch
Одинaction
import React from "react";
import { connect } from "dva";
import styles from "./IndexPage.css";
class IndexPage extends React.Component {
componentDidMount() {
console.log(this.props);
}
render() {
const { dispatch, count } = this.props;
return (
<div className={styles.normal}>
<div className={styles.record}>Highest Record: {count.record}</div>
{/* // 将count的record输出 */}
<div className={styles.current}>{count.current}</div>
<div className={styles.button}>
<button
onClick={() => {
dispatch({ type: "count/add" });
}}
>
+
</button>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return { count: state.count };
} // 获取state
export default connect(mapStateToProps)(IndexPage);
Эффект следующий:
5. Далее используемeffect
Имитировать запрос интерфейса данных, после возврата передатьyield put()
изменить соответствующийstate
(1) Сначала заменим соответствующийmodels/example.js
изeffect
effects: {
*add(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'minus' });
},
},
(2) здесьdelay
, пишем функцию задержки, мы вutils
Напишиutils.js
, функция общего интерфейса запросов будет написана наservers
папка.
export function delay(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}
(3) Тогда вmodels/example.js
импортировать этоutils.js
import { delay } from '../utils/utils';
6. Чтобы подписаться на события клавиатуры, используйтеsubscriptions
, когда пользователь нажимаетcommand+up
Триггер при добавлении чиселaction
(1) Вам необходимо установить этот мастер ключей зависимостей
npm install keymaster --save
(2) вmodels/example.js
Внесите следующие изменения здесьwindows
серединаup
это клавиатура↑
.
import key from 'keymaster';
...
app.model({
namespace: 'count',
+ subscriptions: {
+ keyboardWatcher({ dispatch }) {
+ key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) });
+ },
+ },
});
7. Пример, который мы видим, когда продолжаем нажимать+
кнопка, посмотримcurrent
Оно продолжит увеличиваться на единицу, но через 1 с автоматически уменьшится до нуля. Итак, как мы его модифицируем?
(1) мы должныeffect
Отправьте сообщение о добавленииaction
, но мыeffect
Не могу написать так прямо в
effects: {
*add(action, { call, put }) {
yield put({ type: 'add' });
yield call(delay, 1000);
yield put({ type: 'minus' });
},
},
Потому что если так,effect
а такжеreducers
серединаadd
Методы перекрываются, и здесь будет бесконечный цикл, потому что когда компонент отправляетdispatch
когда,model
найдет первымeffect
Внутри метода при повторном обнаруженииadd
, спросит сноваeffect
метод внутри.
(2) следует изменитьreducers
внутри метода, чтобы он не работал сeffect
таким же образом,reducers
серединаadd
изменить наadd1
.
reducers: {
add1(state) {
const newCurrent = state.current + 1;
return { ...state,
record: newCurrent > state.record ? newCurrent : state.record,
current: newCurrent,
};
},
minus(state) {
return { ...state, current: state.current - 1};
},
},
effects: {
*add(action, { call, put }) {
yield put({ type: 'add1' });
yield call(delay, 1000);
yield put({ type: 'minus' });
},
},
Эпилог
оdva
обрамленныйmodel
Суммировать
1.state
здесь
state
использовать доstate
Концепция та же, только приоритет у нее ниже, чем у инициализации, но в проектеstate
В основном это определено здесь.
2.namespace
model
пространство имен, но и его глобальноеstate
В свойстве можно использовать только строки, которые мы отправляем в поле sendaction
соответствующемуreducer
, вам нужно будет использоватьnamespace
.
3.Reducer
к
key/value
определение форматаreducer
Для обработки синхронной операции единственная модификацияstate
Место. Зависит отaction
вызывать. На самом деле чистая функция.
4.Effect
Используется для обработки асинхронных операций и бизнес-логики без прямого изменения.
state
проще говоря, заключается в получении данных с сервера и инициированииaction
сдаватьreducer
Место.
который он использовалredux-saga
, который содержит несколько часто используемых функций.
*add(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'minus' });
},
5.Effects
(1) put
, используется для запуска действия
yield put({ type: '',payload:'' });
(2)call
Используется для асинхронной логической обработки, поддерживает Promise
const result= yield call(fetch,'');
(3)select
Используется для получения данных из состояния
const todo = yield select(state=>state.todo);
6.Subscription
subscription
это подписка, используемая для подписки на источник данных, а затем по мере необходимостиdispatch
соответствующийactio
н. существуетapp.start()
выполняется, когда источником данных может быть текущее время, текущая страницаurl
, серверwebsocket
соединять,history
Изменение маршрута и т.д.