<p>Введение в два</p>

Созданный на 24 июн. 2016  ·  76Комментарии  ·  Источник: dvajs/dva

Новых понятий нет, все стары.

Почему два?

После периода самостоятельного изучения или обучения каждый должен быть в состоянии понять концепцию избыточности и признать, что такое управление потоком данных может сделать приложение более управляемым, а логику — более ясной.

Но тогда обычно возникает такой вопрос: слишком много понятий, а редюсер, сага и экшен все разделены (подфайлы).

Проблема в следующем:

  • Стоимость редактирования высока, и вам нужно переключаться между редуктором, сагой и экшеном.
  • Неудобно организовывать бизнес-модель (или модель предметной области). Например, после того, как мы напишем список пользователей, чтобы написать список продуктов, нам нужно скопировать много файлов.

И некоторые другие:

  • Написание саги слишком сложно, каждый раз, когда вы слушаете действие, вам нужно пройти процесс fork -> watcher -> worker
  • проблема с записью записи
  • ...

И для решения этих задач используется два.

Что такое два?

dva — это облегченный пакет, основанный на существующей архитектуре приложения (redux + react-router + redux-saga и т. д.), без введения каких-либо новых концепций, а общий код составляет менее 100 строк. (Вдохновленный вязом и чу.)

dva — это фреймворк, а не библиотека, он, как и emberjs, наглядно подскажет, как должен быть написан каждый компонент, что более контролируемо для команды. Кроме того, dva инкапсулирует все остальные зависимости, кроме react и react-dom, которые являются одноранговыми зависимостями.

При реализации dva старайтесь не создавать новый синтаксис, а использовать синтаксис самой библиотеки зависимостей, такой как определение маршрутизатора или синтаксис JSX реакции-маршрутизатора (динамическая конфигурация — это соображение производительности, которое будет поддерживаться позже).

Суть его в том, чтобы предоставить метод app.model , который используется для инкапсуляции редуктора, InitialState, действия и саги вместе, например:

app.model({
  namespace: 'products',
  state: {
    list: [],
    loading: false,
  },
  subscriptions: [
    function(dispatch) {
      dispatch({type: 'products/query'});
    },
  ],
  effects: {
    ['products/query']: function*() {
      yield call(delay(800));
      yield put({
        type: 'products/query/success',
        payload: ['ant-tool', 'roof'],
      });
    },
  },
  reducers: {
    ['products/query'](state) {
      return { ...state, loading: true, };
    },
    ['products/query/success'](state, { payload }) {
      return { ...state, loading: false, list: payload };
    },
  },
});

До dva мы обычно создавали файлы sagas/products.js , reducers/products.js и actions/products.js , а затем переключались между этими файлами.

Введите ключи этих моделей: (при условии, что вы уже знакомы с архитектурой приложения redux, redux-saga)

  • namespace — соответствует ключевому значению редуктора при объединении в rootReducer
  • состояние - соответствует начальному состоянию редуктора
  • подписка — новая концепция [email protected] , выполняется после готовности dom, здесь без объяснений, см.: Прощай, FRP
  • эффекты - соответствует саге и упрощает использование
  • редукторы

Как использовать

Обратитесь к примерам:

Дорожная карта

  • [x] Поддержка горячей замены devtool
  • [x] Маршрутизатор поддерживает динамическую конфигурацию
  • [x] Эффекты должны поддерживать больше режимов саги
  • [ ] Effects рассматривает возможность расширения доступа к thunk, promise, observable и другим решениям, основная цель — совместимость с IE8.
  • [ ] Передавать диспетчеризацию между компонентами слишком хлопотно, рассмотрим следующий план
  • [x] Решение для модульного тестирования
  • [x] Другие примеры: todolist, пользователи в antd-init, популярные продукты

    Вопросы-Ответы

Поддержка уровня средств разработки?

В дополнение к горячей замене, которую еще предстоит адаптировать, совместимы другие, такие как redux-devtool, css livereload и т. д.

Он уже доступен для среды сборки?

Могу.

Включает ли он все функции предыдущей архитектуры приложений redux + redux-saga?

да.

Совместимость с браузером?

IE8 не поддерживает его, потому что используется redux-saga. (Позже мы рассмотрим расширенную поддержку thunks, promises, observables и т. д. в слое эффектов)

Самый полезный комментарий

Быть оживлённым с помощью редукса - это просто Евангелие. Это слишком просто и элегантно. Великая хвала! ! !

Кстати, я случайно увидел сегодня, что иностранец сделал репост в Твиттере, я думал, что это написал иностранец, но я не ожидал, что это одноклассник Alipay, 👍

Все 76 Комментарий

Быть оживлённым с помощью редукса - это просто Евангелие. Это слишком просто и элегантно. Великая хвала! ! !

Кстати, я случайно увидел сегодня, что иностранец сделал репост в Твиттере, я думал, что это написал иностранец, но я не ожидал, что это одноклассник Alipay, 👍

С нетерпением жду расширения эффектов

Использует ли производственная среда Alipay эту архитектуру?

@besteric dva только что вышел, и он еще не применялся, но архитектура приложения , стоящая за ним, использовалась некоторое время.

Редуктор можно записать так:

const reducer = (state, { type, payload }) => {
  switch (type) {
    case 'products/query':
      return { ...state, loading: true, };
    case 'products/query/success':
      return { ...state, loading: false, list: payload };
    default
      return state;
  }
}

app.model({
  reducer
})

Это позволяет применять к редюсеру некоторые методы более высокого порядка.

Хвала, я написал несколько демок и есть только одна проблема, модель можно использовать только
app.model(Model1); app.model(Model2);
Является ли этот метод для завершения комбинации, на самом деле, я думаю, что это идеально
app.model([Model1,Model2])
какой-то тип

Передавать диспетчеризацию между компонентами слишком сложно, рассмотрите следующее решение

Не использовать bindActionCreators ?

Является ли конкретный сценарий расширенного использования редуктора @yesmeck только redo/undo ? Я не хочу, чтобы dva был слишком гибким, и я рассмотрю возможность добавления его через аддон в будущем.

Мы многое используем в нашем проекте, например, мы будем извлекать похожие части нескольких редьюсеров в высокоуровневый метод для модификации исходного редьюсера, и есть высокоуровневые методы, которые позволяют редюсеру сбрасывать состояние, когда маршрут изменения. , а это https://github.com/erikras/multireducer

@ Tinker404 Я чувствую, что было бы понятнее объявить модель отдельно, и было бы проще добавлять и удалять. Я бы написал это:

app.model(require('../models/a'));
app.model(require('../models/b'));

@JimmyLv лично предпочитает не использовать actionCreator, а просто dispatch .

@yesmeck хорошо, я подумаю об этом еще раз.

Существуют также методы более высокого порядка, которые позволяют редьюсеру сбрасывать состояние при изменении маршрута.

Я считаю, что этот сценарий более уместен, если подписаться на изменения маршрутизации в subscriptions , а затем сбросить состояние с помощью действия. Или есть какое-то преимущество в использовании метода редуктора-энхансера?

Я чувствую, что этот сценарий более уместен, если подписаться на маршрутизацию изменений в подписках, а затем сбросить состояние с помощью действия.

В этом случае каждый редьюсер, который необходимо сбросить, должен написать логику сброса.Если мы используем высокоуровневый метод, нам нужно сделать это только сейчас:

combineReducers({
  products: composeReducers({  // composeReducers 的实现见下面
    recycle(LOCATION_CHANGE, initialState),  // recycle 用来在路由变化时重置状态
    products
  })
})

Другой сценарий - та же логика, о которой я говорю, об извлечении разных редукторов. Например, есть список продуктов и список пользователей, а их редюсеры такие:

// reducers/products.js
const reducer = (state, { type, action}) => {
  switch (type) {
    case 'products/FETCH_SUCCESS':
      return {
        ...state,
        loading: false,
        list: payload
      }
    default:
      return state
  }
}
// reducers/users.js
const reducer = (state, { type, payload}) => {
  switch (type) {
    case 'users/FETCH_SUCCESS':
      return {
        ...state,
        loading: false,
        list: payload
      }
    default:
      return state
  }
}

Здесь два редуктора почти одинаковы, поэтому мы извлекаем его и пишем редуктор списка:

const list = (actionType) => {
  return (state, { type, payload }) => {
    switch (type) {
      case actionType:
        return {
          ...state,
          loading: false,
          list: payload
        }
        break;
      default:
        return state
    }
  }
}

Затем мы реализуем composeReducers , чтобы объединить эти 3 редуктора:

function composeReducers(...reducers) {
  return (state, action) => {
    if (reducers.length === 0) {
      return state
    }

    const last = reducers[reducers.length - 1]
    const rest = reducers.slice(0, -1)

    return rest.reduceRight((enhanced, reducer) => reducer(enhanced, action), last(state, action))
  }
}

Таким образом, редюсер для списка продуктов и списка пользователей становится таким:

// reducers/products.js
const reducer = (state, { type, payload}) => {
  // 其他逻辑
}

export default composeReducer(reducer, list('products/FETCH_SUCCESS'))
// reducers/users.js
const reducer = (state, { type, payload}) => {
  // 其他逻辑
}

export default composeReducer(reducer, list('users/FETCH_SUCCESS'))

list — это всего лишь пример, на самом деле в проекте много редьюсеров, имеющих одинаковую логику.

@yesmeck 👍, раньше роль редуктора-энхансера недооценивали.

@sorrycc можешь сказать почему? Явно вызывается со сравнением dispatch ?

@ Tinker404 Я чувствую, что было бы понятнее объявить модель отдельно, и было бы проще добавлять и удалять. Я бы написал это:
app.model (требуется ('../models/a'));
app.model (требуется ('../models/b'));

Я также предлагаю метод, который может передавать несколько моделей одновременно.В больших проектах может быть много моделей.Я сейчас требую (импортирую) их все, а затем моделирую каждую модель по очереди, что не очень удобно.Мой текущий способ письменности это:

// models是个文件夹,有很多model
import models from './models';

models.forEach((m)=>{
    app.model(m);
});

// models.js
const context = require.context('./', false, /\.js$/);
const keys = context.keys().filter(item => item !== './index.js');
const models = [];
for (let i = 0; i < keys.length; i++) {
  models.push(context(keys[i]));
}
export default models;

Это очень D.VA.

Я нашел использование компонента формы antd в пользовательской панели. Я помню, что его нельзя использовать для чистого компонента. Возможно ли это сейчас?

@codering Я не помню, чтобы были ограничения, проблемы с antd можно задать по адресу https://github.com/ant-design/ant-design/issues .

https://github.com/react-component/form/blob/master/README.md
Об этом говорится в ПРИМЕЧАНИИ.

Привет, я хочу использовать ваш dva. В настоящее время я использую структуру каталогов, сгенерированную скаффолдингом React Webpack Redux. Я изменил код со ссылкой на пример панели пользователя в вашем примере, но после запуска ничего нет. Можете ли вы помочь мне узнать где это?Что-то пошло не так,адрес моего проекта: https://github.com/baiyulong/lenovo_parts

@baiyulong, почему бы не сделать это напрямую на основе структуры каталогов пользовательской панели?

@sorrycc Сейчас я использую структуру каталогов user-dashboard Есть ли какая-то специальная обработка или запись для маршрутизации dva?
export default function({ history }) {
return (
<Router history={history}>
<IndexRoute component={HomePage} />
<Route path='/' component={HomePage}>
<Route path='/create' component={CreateOrder} />
</Route>
</Router>
)
}
Этот маршрут я написал, HomePage может, я написал ссылку <Link to='/create'>Create</Link> , я не могу перейти к компоненту CreateOrder после нажатия на нее

Нет специального способа написать маршрут @baiyulong dva , попробуйте:

  1. Есть ли ошибка
  2. Попробуйте получить прямой доступ к маршруту /create

@nikogu большое спасибо, я буду в порядке после того, как вытащу гнездо

Здравствуйте, может ли dva поддерживать горячую загрузку моделей?

@kkkf1190 рассматривает это и поддержит.

👍

Просто хотел сказать спасибо. . .

Я всегда думал, что леса vue-cli vuejs очень хороши.После прочтения этого мое мышление полностью изменилось.

Очень замечательный кадр! Некоторое время занимался исследованиями. @sorrycc Я хочу задать Юнде два вопроса:

  1. Можно ли идеально использовать dva в нативных проектах?
  2. Может ли dva+reactjs хорошо поддерживать рендеринг на стороне сервера?

@freemember007

  1. Поддержите реагирование, справочный пример: https://github.com/sorrycc/dva-example-react-native
  2. Теоретически проблем в работе сервера нет, и redux, и react-router за ним поддерживают SSR, но применить его к dva потребуется некоторое время, потому что соответствующая логика должна быть выправлена ​​и хорошо упакована.

@sorrycc Есть ли сейчас решение для поддержки редуктора более высокого порядка? В нашем проекте используется много редукторов высокого порядка из-за повторного использования.

Поддерживается @ancheel , может быть глобальным или локальным, пример использования: https://github.com/dvajs/dva/blob/master/test/reducers-test.js

После того, как состояние модели изменено, как изменить его снова, эта проблема всегда возникает сейчас
antd.js:32924 Предупреждение: setState(...): Невозможно обновить во время существующего перехода состояния (например, внутри render или конструктора другого компонента).Методы рендеринга должны быть чистой функцией свойств и состояния; конструктор side-effects — это антишаблон, но его можно переместить в componentWillMount .

Очень интересно, попробуйте использовать его в производственной среде, надеюсь на дальнейшую оптимизацию и улучшение

нерф это!

Хорошая работа. Спасибо!

@sorrycc С нетерпением ждем поддержки рендеринга на стороне сервера!

Поддерживается @mountainmoon , см. https://github.com/sorrycc/dva-boilerplate-isomorphic .

Пришла волна колес :+1:

Привет, я только что связался с изучением этого два.После чтения кода в течение нескольких дней, у меня есть несколько вопросов в моем сердце.Я хотел бы спросить:
Я видел, что ваши демо все одностраничные приложения, но все они многостраничные приложения в разработке.Я хотел бы спросить, если маршрутизация не используется в разработке многостраничных приложений, как вместо этого загружать компоненты, может быть, я спрашиваю идиота Это немного сбивает с толку, потому что я не использую маршрутизацию, поэтому слушатель, установленный в моделях, не ясно, где запускать:
history.listen(местоположение => {
if(location.pathname === '/users') {
отправлять({
тип: 'успех запроса',
полезная нагрузка: {}
})
}
})
PS: при загрузке данных в методе querySuccess и использовании экспорта по умолчанию connect(mapStateToProps)(Users); также сообщается об ошибке:
connect.js: 41 Uncaught TypeError: невозможно вызвать класс как функцию
Я чувствую себя идиотом в одно мгновение, я не знаю, смогу ли я побеспокоить вас, чтобы объяснить мне это, спасибо!

Почему два? пожалуйста, по английски

Мне не очень нравится такой способ написания.

@codering вы упомянули об использовании компонентов формы antd в пользовательской панели инструментов. Я помню, что его нельзя использовать для чистых компонентов. Возможно ли это сейчас?
Я также сталкивался с этим чаще всего.Если это чистый функциональный компонент, функция getFieldDecorator не может быть получена через props.form.getFieldDecorator.Если вы используете расширения для создания компонента, вы можете получить его.
Я не знаю, есть ли у Бога решение @sorrycc

Не могли бы вы запустить ту же страницу на английском языке? Мы этого понять не в состоянии, да и зачем нам два.

Здравствуйте, если это большой проект, его состояние будет очень большим, и его будет очень сложно обрабатывать. Следует ли разбить его на несколько моделей?

@yazhou-zyz У меня та же проблема, что и у тебя:
Предупреждение: setState(...): Невозможно обновить во время существующего перехода состояния (например, внутри рендеринга или конструктора другого компонента). Методы рендеринга должны быть чистой функцией свойств и состояния; побочные эффекты конструктора являются анти-шаблоном, но можно переместить в componentWillMount.
Я хотел бы спросить, как вы ее решили?

Учить

продолжай учиться

dva имеет большое справочное значение для строительных проектов.

хорошая работа~

Где найти документы на английском??? Перевод темы с помощью движков переводчика проблематичен, а понимания недостаточно. С английским вы, ребята, можете достичь мира. Продолжайте хорошую работу!! :ракета:

dva не пробовали в версиях React-native 0.47.X и React16.0.0.

@vecold всегда мог его использовать, говоря, что код приглашения или сообщение об ошибке нельзя использовать.

Есть ли шанс, что мы сможем получить английский перевод документов?
Спасибо!

В бизнес-коде такой пример распространен.Локальное обновление состояния может повлиять на все тело.Многие места, которые не нуждаются в повторной отрисовке, также перерисовываются, что сильно снижает производительность страницы. Можно ли добавить эту функцию для автоматического анализа состояния, от которого зависит redux connect, чтобы уменьшить ненужные вычисления mapStateToProps и повторный рендеринг 👍

отлично
но он создает всю страницу, когда я надеюсь создать одну страницу

_неофициальный перевод_

Почему Два?

Редукс хорош. Но слишком много концепций, разделенных редюсеров, саг и экшенов (разбитых по разным файлам)

  1. Необходимо часто переключаться между редьюсерами, мудрецами и действиями.
  2. Неудобство для организации бизнес-моделей (или моделей предметной области). Для exp., когда у нас уже есть user_list, и требуется product_list, то необходимо продублировать копию файла
  3. Сагу трудно писать. Вы должны сделать fork -> watcher -> worker для каждого отдельного действия.
  4. Вход утомительный и сложный

Что Два?

Это облегченная оболочка над существующим фреймворком (redux + react-router + redux-saga...). Никакой новой концепции. < 100 строк кода. (Вдохновлено вязом и чу. )

Это фреймворк, а не библиотека. Как и Ember.js, он ограничивает способ написания каждой части. Это более контролируемо для командной работы. Dva инкапсулирует все зависимости, кроме react и react-dom, как peerDependencies.

Его реализация вводит как можно меньше новых синтаксисов. Он повторно использует зависимости. Например, определение маршрутизатора точно такое же, как JSX для реактивного маршрутизатора.

Основная функциональность app.model . Он инкапсулирует редуктор, InitialState, действие, сагу в целом.

app.model({
  namespace: 'products',
  state: {
    list: [],
    loading: false,
  },
  subscriptions: [
    function(dispatch) {
      dispatch({type: 'products/query'});
    },
  ],
  effects: {
    ['products/query']: function*() {
      yield call(delay(800));
      yield put({
        type: 'products/query/success',
        payload: ['ant-tool', 'roof'],
      });
    },
  },
  reducers: {
    ['products/query'](state) {
      return { ...state, loading: true, };
    },
    ['products/query/success'](state, { payload }) {
      return { ...state, loading: false, list: payload };
    },
  },
});

Раньше мы создавали sagas/products.js, reducers/products.js actions/products.js и переключались между ними.

ключевой момент:

  • пространство имен: key объекта reducer в его объекте rootReducer
  • состояние: initialState из reducer
  • подписка: новая концепция [email protected] , выполняется, когда дом готов: Прощай, FRP
  • эффекты: легкий шалфей
  • редукторы

Как использовать

См. примеры

Дорожная карта

  • devtool горячая перезагрузка
  • Динамическая конфигурация для маршрутизатора
  • Effects поддерживает больше моделей saga
  • Модульный тест
  • Дополнительные примеры: todolist, пользователи в antd-init, популярные продукты

Вопросы-Ответы

Dev-tool поддерживает?

Совместим с redux-devtool, css livereload. Нужно больше работы для горячей перезагрузки

Хорошо для prod env?

Конечно

Включая все функции redux + redux-saga?

да

Совместимость с браузерами?

Нет IE8 из-за редукции. (Позже могут применяться преобразователь, обещание, наблюдаемые в качестве расширений на уровне эффектов)

пожалуйста, подобное

['products/query']: function*() {}
['products/query'](state) {}

Каков синтаксис? Можно ли использовать массивы в качестве имен функций?

@clemTheDasher Имя функции может быть вычислено ключом ( НЕ массивом) в JavaScript. Более подробная ссылка на определения методов |

var obj = {
  property( parameters… ) {},
  *generator( parameters… ) {},
  async property( parameters… ) {},
  async* generator( parameters… ) {},

  // with computed keys:
  [property]( parameters… ) {},
  *[generator]( parameters… ) {},
  async [property]( parameters… ) {},

  // compare getter/setter syntax:
  get property() {},
  set property(value) {}
};

Отчеты новичков, заходите сюда и продолжайте усердно работать над изучением фронтенда

@clemTheDasher Это вычисляемое свойство.

Учить!

взгляни на бога

Слава Богу, спасибо за открытый исходный код

мне нельзя учиться у вас, ребята!

Я узнал, спасибо за то, что у нас есть такой удобный фреймворк для использования

Демо-ссылки на github устарели.

@sorrycc поддерживает ли dva рендеринг на стороне сервера?

Редуктор можно записать так:

const reducer = (state, { type, payload }) => {
  switch (type) {
    case 'products/query':
      return { ...state, loading: true, };
    case 'products/query/success':
      return { ...state, loading: false, list: payload };
    default
      return state;
  }
}

app.model({
  reducer
})

Это позволяет применять к редюсеру некоторые методы более высокого порядка.

Стиль написания Redux лаконичен, и для изменения состояния требуется всего одна строка, но кажется, что несколько строк кода пишутся вместе через синтаксический сахар. Но мне все еще нужно использовать ...state для доставки оставшегося статуса на следующую остановку, иначе статус будет неполным. Другими словами, на этапе редукции какое-то состояние может быть потеряно, если оно записано неправильно.

В некотором смысле идея Vuex легче читается и более естественна. Напишите что-то вроде этого (не совсем так).

const mutation = {
  ['products/query'](state) {
    state.loading = true
  },
  ['products/query/success'](state, payload) {
    state.loading = false
    state.list = payload
  }
}

Что касается кода, меня волнует только то, какое состояние я (синхронно) изменяю. Vuex также должен обернуть слой снаружи для доставки состояния следующей остановки. Возможно, перед доставкой также проводятся некоторые защитные проверки (угадывание) или подбрасываются крючки.

Спросите меня, если пример страницы официального сайта dva не может выйти и сообщить об ошибке, это обновление?

пожалуйста, подобное

['products/query']: function*() {}
['products/query'](state) {}

Каков синтаксис? Можно ли использовать массивы в качестве имен функций?

ES6 позволяет литералам определять объекты (выражения) как имя свойства объекта, то есть помещать выражение в квадратные скобки.
Такие как

obj = {
  ['xxname']: 'what ever you defined',
  ['xxyy'](args) {
    ....
  }
}

Есть вопрос, 'products/query' используется для обработки вызова редьюсеров, и он связан с пространством имён через строку.Позже, если проект станет больше, например сотни методов. Если мое пространство имен должно быть изменено. Сменить сотню методов?

@yesmeck 👍, раньше роль редуктора-энхансера недооценивали.

Не знаю, есть ли здесь поддержка?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги