Поговорите о Concent & Recoil и изучите новый режим разработки потока данных реакции.

JavaScript React.js
Поговорите о Concent & Recoil и изучите новый режим разработки потока данных реакции.

Открытый исходный код не так прост, спасибо за вашу поддержку,❤ отметьте меня, если вам нравится концепт ^_^

Преамбула

ранее опубликованная статьяКонкуренция Redux, mobx, концентрата, посмотрите, как молодое поколение играет против предшественников, привлекая многих заинтересованных друзей присоединиться к группе и начать понимать и использоватьconcent, и получили много положительных отзывов, что очень помогло им улучшить свой опыт разработки.Хотя количество людей в группе пока невелико, все полны энтузиазма, атмосфера технических дискуссий сильна, и они чувствительны ко многим новым технологиям . , как новейшее решение для управления статусами от facebook, которое постепенно упоминается все больше и больше в прошлом месяцеrecoil, Хотя он все еще находится в экспериментальном состоянии, кажется, что все уже начали пробовать его в частном порядке.В конце концов, он родился в известной семье и имеет одобрение FB, так что он определенно будет сиять.

Но после того, как я испытал отдачу, я был очень впечатлен разрекламированнымточное обновлениеЯ придерживаюсь скептического отношения, и есть некоторые вводящие в заблуждение подозрения. Этот пункт будет проанализирован отдельно ниже. Является ли это заблуждением, читатели, естественно, могут сделать выводы после прочтения этой статьи. Короче говоря, эта статья в основном анализируетConcentа такжеRecoilразличия стилей кода и изучить их новое влияние на нашу будущую модель разработки, а также то, какие изменения в мышлении необходимо сделать.

Три основных типа решений для потоков данных

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

  • жанр редукса

redux и другие работы, производные от redux, а также работы, похожие на идеи redux, репрезентативные работы включают dva, rematch и т. д.

  • жанр мобкс

С помощью definePerperty и Proxy для завершения захвата данных, чтобы достичь цели адаптивного программирования, также есть много работ, таких как mobx, например, dob и так далее.

  • Жанр контекста

Контекст здесь относится к API-интерфейсу контекста, который поставляется с React. Решения для потока данных, основанные на API-интерфейсе контекста, обычно легковесны, просты в использовании и имеют мало обзоров. Репрезентативные работы включают неустановленные, консервативные и т. д. Основной код большинства произведения не могут превышать 500 строк.

Здесь мы видимRecoilК какой категории он должен относиться? Очевидно, что по своим характеристикам он относится к жанру Context, поэтому основная облегченная пара, о которой мы упоминали выше, этоRecoilОн больше не применяется, откройте его библиотеку исходного кода и обнаружите, что код не закончен в сотнях строк, поэтому на основеContext apiОн не обязательно легкий, если он простой в использовании и мощный, это видно из этогоfacebookправильноRecoilБудьте амбициозны и подавайте большие надежды.

Мы также смотрим наConcentК какой категории относится?Concentсуществуетv2После версии механизм отслеживания данных был реорганизован, а функции defineProperty и Proxy были включены, так что реагирующее приложение не только сохранило неизменное преследование, но также получило преимущества повышения производительности за счет сбора зависимостей во время выполнения и точного обновления пользовательского интерфейса. и прокси включены, тогда это выглядит такConcentДолжен принадлежать к жанру mobx?

ФактическиConcentОн принадлежит к совершенно новому жанру, не полагается на API контекста реакции, не разрушает форму самого компонента реакции, поддерживает философию стремления к неизменности и только строит механизм распределения состояний логического уровня и планирования поверх реагирующих собственный механизм планирования рендеринга, defineProperty и Proxy используются только для помощи в сборе экземпляров и зависимости производных данных от данных модуля, в то время как изменение ввода данных по-прежнему setState (или диспетчеризация, вызов, синхронизация на основе инкапсуляции setState), что позволяетConcentОн может получить доступ к реагирующим приложениям с нулевым вторжением, по-настоящему plug-and-play и неосознанным доступом.

Подключи и играйОсновной принцип заключается в том,ConcentОн создал глобальный контекст, параллельный среде выполнения реакции, тщательно поддерживал связь атрибуции между модулем и экземпляром и принял запись обновления setState экземпляра компонента, сохранив исходный setState как reactSetState. В дополнение к вызову reactSetState для обновления текущего экземпляра пользовательского интерфейса, в то же время разумно определите, есть ли другие экземпляры отправленного состояния, которые заботятся о его изменениях, а затем выведите их для выполнения reactSetState этих экземпляров по очереди, тем самым достижение цели синхронизации всех состояний.

Откатить первый опыт

Давайте возьмем часто используемый счетчик в качестве примера, чтобы ознакомиться с ним.RecoilПредоставьте четыре часто используемых API

  • атом, определяет состояние
  • селектор, определяет производные данные
  • useRecoilState, состояние потребления
  • useRecoilValue, использовать производные данные

определить состояние

внешнее использованиеatomИнтерфейс, определите ключ какnum, начальное значение равно0положение дел

const numState = atom({
  key: "num",
  default: 0
});

Определение производных данных

внешнее использованиеselectorИнтерфейс, определите ключ какnumx10, начальное значение зависит отnumStateвычислено снова

const numx10Val = selector({
  key: "numx10",
  get: ({ get }) => {
    const num = get(numState);
    return num * 10;
  }
});

Определение асинхронных производных данных

selectorизgetПоддержка определения асинхронных функций

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

const delay = () => new Promise(r => setTimeout(r, 1000));

const asyncNumx10Val = selector({
  key: "asyncNumx10",
  get: async ({ get }) => {
    // !!!这句话不能放在delay之下, selector需要同步的确定依赖
    const num = get(numState);
    await delay();
    return num * 10;
  }
});

статус потребления

используемый компонентuseRecoilStateИнтерфейс, перейдите в состояние, которое вы хотите получить (путемatomсозданный)

const NumView = () => {
  const [num, setNum] = useRecoilState(numState);

  const add = ()=>setNum(num+1);

  return (
    <div>
      {num}<br/>
      <button onClick={add}>add</button>
    </div>
  );
}

Использовать производные данные

используемый компонентuseRecoilValueинтерфейс, передайте производные данные, которые вы хотите получить (путемselectorсоздан), через этот интерфейс могут быть получены как синхронно полученные данные, так и асинхронно полученные данные

const NumValView = () => {
  const numx10 = useRecoilValue(numx10Val);
  const asyncNumx10 = useRecoilValue(asyncNumx10Val);

  return (
    <div>
      numx10 :{numx10}<br/>
    </div>
  );
};

сделать их, чтобы увидеть результат

Выставьте два определенных компонента,Посмотреть онлайн-примеры

export default ()=>{
  return (
    <>
      <NumView />
      <NumValView />
    </>
  );
};

упаковка узла верхнего уровняReact.Suspenseа такжеRecoilRoot, первый используется для удовлетворения потребностей асинхронных вычислительных функций, а второй используется для вводаRecoilконтекст

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <React.Suspense fallback={<div>Loading...</div>}>
      <RecoilRoot>
        <Demo />
      </RecoilRoot>
    </React.Suspense>
  </React.StrictMode>,
  rootElement
);

Concent первый опыт

Если вы читали документ concent (еще в разработке...), то некоторые люди могут подумать, что API слишком много и их трудно запомнить.На самом деле, большинство из них являются необязательным синтаксическим сахаром.В качестве примера возьмем counter , нужно использовать только следующие два API.

  • запустить, определить состояние модуля (обязательно), расчет модуля (необязательно), наблюдение за модулем (необязательно)

После запуска интерфейса запуска будет создан контекстный глобальный контекст.

  • setState, изменить состояние

Определить состояние и изменить состояние

В следующем примере мы сначала покидаем пользовательский интерфейс и непосредственно выполняем задачу определения состояния и изменения состояния.

import { run, setState, getState } from "concent";

run({
  counter: {// 声明一个counter模块
    state: { num: 1 }, // 定义状态
  }
});

console.log(getState('counter').num);// log: 1
setState('counter', {num:10});// 修改counter模块的num值为10
console.log(getState('counter').num);// log: 10

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

Ввести редуктор

В приведенном выше примере мы напрямую вызываемsetStateИзмените данные, но реальная ситуация такова, что существует много синхронных или асинхронных операций бизнес-логики до того, как данные будут отправлены, поэтому мы добавляем в модульreducerОпределение, используемое для объявления набора методов, изменяющих данные.

import { run, dispatch, getState } from "concent";

const delay = () => new Promise(r => setTimeout(r, 1000));

const state = () => ({ num: 1 });// 状态声明
const reducer = {// reducer声明
  inc(payload, moduleState) {
    return { num: moduleState.num + 1 };
  },
  async asyncInc(payload, moduleState) {
    await delay();
    return { num: moduleState.num + 1 };
  }
};

run({
  counter: { state, reducer }
});

Затем мы используемdispatchчтобы вызвать метод для изменения состояния

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

import { dispatch } from "concent";

(async ()=>{
  console.log(getState("counter").num);// log 1
  await dispatch("counter/inc");// 同步修改
  console.log(getState("counter").num);// log 2
  await dispatch("counter/asyncInc");// 异步修改
  console.log(getState("counter").num);// log 3
})()

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

import { dispatch } from "concent";

await dispatch("counter/inc");
// 修改为
await dispatch(reducer.inc);

фактическиrunинтерфейс определенreducerколлекция былаconcentцентрализованно и позволяют пользователямreducer.${moduleName}.${methodName}метод, так что здесь мы даже можем вызвать его на основеreducerпозвонить

import { reducer as ccReducer } from 'concent';

await dispatch(reducer.inc);
// 修改为
await ccReducer.counter.inc();

Доступ к реакции

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

  • зарегистрируйте, зарегистрируйте компоненты класса как компоненты контента
  • useConcent, зарегистрируйте компонент функции как компонент контента
import { register, useConcent } from "concent";

@register("counter")
class ClsComp extends React.Component {
  changeNum = () => this.setState({ num: 10 })
  render() {
    return (
      <div>
        <h1>class comp: {this.state.num}</h1>
        <button onClick={this.changeNum}>changeNum</button>
      </div>
    );
  }
}

function FnComp() {
  const { state, setState } = useConcent("counter");
  const changeNum = () => setState({ num: 20 });
  
  return (
    <div>
      <h1>fn comp: {state.num}</h1>
      <button onClick={changeNum}>changeNum</button>
    </div>
  );
}

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

сделать их, чтобы увидеть результат

Онлайн-пример

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <div>
      <ClsComp />
      <FnComp />
    </div>
  </React.StrictMode>,
  rootElement
);

В сравненииRecoil, мы находим, что нет верхнего слоя и нетProviderилиRootПодобные пакеты компонентов, реагирующие компоненты были подключены к концентрату, чтобы обеспечить настоящий plug-and-play и неосведомленный доступ, и в то же времяapiзарезервировано сreactСогласованное написание.

Редуктор вызовов компонентов

concent генерирует контекст экземпляра для каждого экземпляра компонента, что удобно для пользователей, чтобы напрямую передатьctx.mrвызвать метод редуктора

mr — это аббревиатура от moduleReducer, также разрешено писать напрямую как ctx.moduleReducer.

//  --------- 对于类组件 -----------
changeNum = () => this.setState({ num: 10 })
// ===> 修改为
changeNum = () => this.ctx.mr.inc(10);// or this.ctx.mr.asynInc(10)

//当然这里也可以写为ctx.dispatch调用,不过更推荐用上面的moduleReducer直接调用
//this.ctx.dispatch('inc', 10); // or this.ctx.dispatch('asynInc', 10)

//  --------- 对于函数组件 -----------
const { state, mr } = useConcent("counter");// useConcent 返回的就是ctx
const changeNum = () => mr.inc(20); // or ctx.mr.asynInc(10)

//对于函数组将同样支持dispatch调用方式
//ctx.dispatch('inc', 10);  // or ctx.dispatch('asynInc', 10)

Функция асинхронного расчета

runРасширения поддерживаются в интерфейсеcomputedАтрибут, то есть набор функций расчета, который позволяет пользователям определять набор производных данных.Они могут быть синхронными или асинхронными.В то же время он поддерживает функцию для использования вывода другой функции в качестве входных данных для выполнения вторичных вычислений. , Входная зависимость расчета собирается автоматически.

 const computed = {// 定义计算函数集合
  numx10({ num }) {
    return num * 10;
  },
  // n:newState, o:oldState, f:fnCtx
  // 结构出num,表示当前计算依赖是num,仅当num发生变化时触发此函数重计算
  async numx10_2({ num }, o, f) {
    // 必需调用setInitialVal给numx10_2一个初始值,
    // 该函数仅在初次computed触发时执行一次
    f.setInitialVal(num * 55);
    await delay();
    return num * 100;
  },
  async numx10_3({ num }, o, f) {
    f.setInitialVal(num * 1);
    await delay();
    // 使用numx10_2再次计算
    const ret = num * f.cuVal.numx10_2;
    if (ret % 40000 === 0) throw new Error("-->mock error");
    return ret;
  }
}

// 配置到counter模块
run({
  counter: { state, reducer, computed }
});

В приведенной выше расчетной функции мы намеренно позволилиnumx10_3В какой-то момент сообщается об ошибке, для этой ошибки мы можемrunВторой бит интерфейсаoptionsОпределяется в конфигурацииerrorHandlerловить.

run({/**storeConfig*/}, {
    errorHandler: (err)=>{
        alert(err.message);
    }
})

Конечно, лучше использоватьconcent-plugin-async-computed-statusПлагины для полного унифицированного управления статусом выполнения всех функций расчета модуля.

import cuStatusPlugin from "concent-plugin-async-computed-status";

run(
  {/**storeConfig*/},
  {
    errorHandler: err => {
      console.error('errorHandler ', err);
      // alert(err.message);
    },
    plugins: [cuStatusPlugin], // 配置异步计算函数执行状态管理插件
  }
);

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

function Test() {
  const { moduleComputed, connectedState, setState, state, ccUniqueKey } = useConcent({
    module: "counter",// 属于counter模块,状态直接从state获得
    connect: ["cuStatus"],// 连接到cuStatus模块,状态从connectedState.{$moduleName}获得
  });
  const changeNum = () => setState({ num: state.num + 1 });
  
  // 获得counter模块的计算函数执行状态
  const counterCuStatus = connectedState.cuStatus.counter;
  // 当然,可以更细粒度的获得指定结算函数的执行状态
  // const {['counter/numx10_2']:num1Status, ['counter/numx10_3']: num2Status} = connectedState.cuStatus;

  return (
    <div>
      {state.num}
      <br />
      {counterCuStatus.done ? moduleComputed.numx10 : 'computing'}
      {/** 此处拿到错误可以用于渲染,当然也抛出去 */}
      {/** 让ErrorBoundary之类的组件捕捉并渲染降级页面 */}
      {counterCuStatus.err ? counterCuStatus.err.message : ''}
      <br />
      {moduleComputed.numx10_2}
      <br />
      {moduleComputed.numx10_3}
      <br />
      <button onClick={changeNum}>changeNum</button>
    </div>
  );
}

Посмотреть онлайн-примеры

точное обновление

я правильно сказалRecoliУпомянулточное обновлениеПоддерживал скептический настрой, есть некоторые обманчивые подозрения, вот и раскроем тайну

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

const NumView = () => {
  const [show, setShow] = useState(true);
  if(show){// error
    const [num, setNum] = useRecoilState(numState);
  }
}

Так что, если пользователь не использует эти данные в определенном состоянии в рендеринге пользовательского интерфейса, что-то изменилось.numзначение все равно сработаетNumViewперерисовывает, ноconcentвырвано из контекста экземпляраstateа такжеmoduleComputedЯвляетсяProxyЦель состоит в том, чтобы собрать зависимости, необходимые для каждого раунда рендеринга в режиме реального времени, что является реальным рендерингом по запросу и точным обновлением.

const NumView = () => {
  const [show, setShow] = useState(true);
  const {state} = useConcent('counter');
  // show为true时,当前实例的渲染对state.num的渲染有依赖
  return {show ? <h1>{state.num}</h1> : 'nothing'}
}

Нажмите здесь, чтобы увидеть примеры кода

Конечно, если пользователю нужно делать другие вещи, когда значение num было отображено после отображения пользовательского интерфейса, что-то вродеuseEffectэффект, concent также поддерживает пользователей, чтобы привлечь его кsetupв, определитьeffectчтобы выполнить требования этого сценария, по сравнению сuseEffect, в настройкеctx.effectВам нужно определить его только один раз, и вам нужно всего лишь передать имя ключа, и концентрат автоматически сравнит значение предыдущего момента и текущего момента, чтобы решить, следует ли запускать функцию побочного эффекта.

conset setup = (ctx)=>{
  ctx.effect(()=>{
    console.log('do something when num changed');
    return ()=>console.log('clear up');
  }, ['num'])
}

function Test1(){
  useConcent({module:'cunter', setup});
  return <h1>for setup<h1/>
}

Для получения дополнительной информации об эффекте и useEffect, пожалуйста, ознакомьтесь с этой статьей.

current mode

О том, поддерживается ли контентcurrent modeЭтот вопрос, вот ответ,concentполностью поддерживается на 100%, или, кроме того, все инструменты управления состоянием, которые в конечном итоге срабатывают,setStateилиforceUpdate, пока мы не пишем код с какими-либо побочными эффектами в процессе рендеринга, пусть тот же вход состояния получает мощность результата рендеринга, то есть вcurrent modeзапустить безопасный код.

current modeЭто просто более требовательно к нашему коду.

// bad
function Test(){
   track.upload('renderTrigger');// 上报渲染触发事件
   return <h1>bad case</h1>
}

// good
function Test(){
   useEffect(()=>{
      // 就算仅执行了一次setState, current mode下该组件可能会重复渲染,
      // 但react内部会保证该副作用只触发一次
      track.upload('renderTrigger');
   })
   return <h1>bad case</h1>
}

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

Так же, для концентрации

const setup = (ctx)=>{
  ctx.effect(()=>{
     // effect是对useEffect的封装,
     // 同样在current mode下该副作用也只触发一次(由react保证)
      track.upload('renderTrigger');
  });
}

// good
function Test2(){
   useConcent({setup})
   return <h1>good case</h1>
}

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

// 假设这是一个渲染很耗时的组件,在current mode模式下可能会被中断渲染
function HeavyComp(){
  const { state } = useConcent({module:'counter'});// 属于counter模块

 // 这里读取了num 和 numBig两个值,收集到了依赖
 // 即当仅当counter模块的num、numBig的发生变化时,才触发其重渲染(最终还是调用setState)
 // 而counter模块的其他值发生变化时,不会触发该实例的setState
  return (
    <div>num: {state.num} numBig: {state.numBig}</div>
  );
}

Наконец-то мы можем разобраться,hookЭто настраиваемый хук (функция без возврата пользовательского интерфейса), который поддерживает удаление используемой логики, а другое управление состоянием просто выполняет еще один уровень работы, помогая пользователям отделить логику от своих правил и, наконец, обработать бизнес-данные обратно вreactкомпонент вызывает свойsetStateилиforceUpdateвызвать повторный рендеринг,current modeВведение не оказывает никакого влияния на существующее управление состоянием или новую схему управления состоянием, а только предъявляет более высокие требования к пользовательскому коду пользовательского интерфейса, чтобы избежатьcurrent modeВызывает трудноисключаемые ошибки

По этой причине react также предоставляет специальныйReact.Strictкомпонент для преднамеренного запуска механизма двойного вызова,Rect js.org/docs/strict..., чтобы помочь пользователям написать более совместимый код реагирования, чтобы адаптироваться к текущему режиму, предоставляемому в будущем.

Все новые возможности реакции на самом делеfiberактивируется, сfiberархитектура, происходящая отhook,time slicing,suspenseи будущееConcurrent Mode, как компоненты класса, так и компоненты функций можно найти вConcurrent ModeРаботайте безопасно, пока соблюдаете правила.

Взято из:реагировать JS.org/docs/strict…

Строгий режим не может автоматически обнаруживать побочные эффекты, но может помочь вам определить их, сделав их немного более детерминированными, преднамеренно дважды вызывая следующие функции:

  • Class component constructor, render, and shouldComponentUpdate methods
  • Class component static getDerivedStateFromProps method
  • Function component bodies
  • State updater functions (the first argument to setState)
  • Functions passed to useState, useMemo, or useReducer

И что,React.StrictНа самом деле, для того, чтобы пользователи могли писатьConcurrent ModeВспомогательный API, предоставляемый кодом, работающим в системе, позволяет пользователям постепенно, шаг за шагом, привыкнуть к этим ограничениям и, наконец, запуститьConcurrent Mode.

Эпилог

RecoilОн выступает за более детальное управление состоянием и производными данными.Демонстрация выглядит простой в написании, но на самом деле она все еще очень громоздка после большого масштаба кода.

// 定义状态
const numState = atom({key:'num', default:0});
const numBigState = atom({key:'numBig', default:100});
// 定义衍生数据
const numx2Val = selector({
  key: "numx2",
  get: ({ get }) => get(numState) * 2,
});
const numBigx2Val = selector({
  key: "numBigx2",
  get: ({ get }) => get(numBigState) * 2,
});
const numSumBigVal = selector({
  key: "numSumBig",
  get: ({ get }) => get(numState) + get(numBigState),
});

// ---> ui处消费状态或衍生数据
const [num] = useRecoilState(numState);
const [numBig] = useRecoilState(numBigState);
const numx2 = useRecoilValue(numx2Val);
const numBigx2 = useRecoilValue(numBigx2Val);
const numSumBig = useRecoilValue(numSumBigVal);

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

run({
  counter: {// 声明一个counter模块
    state: { num: 1, numBig: 100 }, // 定义状态
    computed:{// 定义计算,参数列表里解构具体的状态时确定了依赖
       numx2: ({num})=> num * 2,
       numBigx2: ({numBig})=> numBig * 2,
       numSumBig: ({num, numBig})=> num + numBig,
     }
  },
});

Хотя компоненты и функции класса можно использовать стот же методПерейти к потребительским данным и методам обязательства

// ###### 函数组件
function Demo(){
  const { state, moduleComputed, setState } = useConcent('counter') 
  // ---> ui处消费状态或衍生数据,在ui处结构了才产生依赖
  const { numx2, numBigx2, numSumBig} = moduleComputed;
  const { num, numBig } = state;
  // ... ui logic
}

// ###### 类组件
const DemoCls = register('counter')(
  class DemoCls extends React.Component{
   render(){
      const { state, moduleComputed, setState } = this.ctx; 
      // ---> ui处消费状态或衍生数据,在ui处结构了才产生依赖
      const { numx2, numBigx2, numSumBig} = moduleComputed;
      const { num, numBig } = state;
      // ... ui logic
    }
  }
)

Таким образом, вы получите:

  • Сбор зависимостей во время выполнения, а также соблюдение принципа неизменности реакции
  • Все является функцией (состояние, редуктор, вычисление, просмотр, событие...), может получить более дружественную поддержку ts
  • Компоненты класса и функциональные компоненты могут совместно использовать модель хранилища.
  • Поддержка промежуточного программного обеспечения и механизма подключаемых модулей, легкость совместимости с экосистемой redux.
  • В то же время он поддерживает централизованную и фрактальную конфигурацию модулей, а также синхронную и асинхронную загрузку модулей, что более удобно для эластичного процесса реконструкции крупномасштабных проектов.

❤ отметьте меня, если вам нравится концепт ^_^

Edit on CodeSandbox https://codesandbox.io/s/concent-guide-xvcej

Edit on StackBlitz https://stackblitz.com/edit/cc-multi-ways-to-wirte-code

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