Открытый исходный код не так прост, спасибо за вашу поддержку,❤ отметьте меня, если вам нравится концепт ^_^
Преамбула
ранее опубликованная статьяКонкуренция 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/>
}
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.
- В то же время он поддерживает централизованную и фрактальную конфигурацию модулей, а также синхронную и асинхронную загрузку модулей, что более удобно для эластичного процесса реконструкции крупномасштабных проектов.
❤ отметьте меня, если вам нравится концепт ^_^
Если у вас есть какие-либо вопросы о конценте, вы можете отсканировать код и присоединиться к групповой консультации.Мы постараемся ответить на ваши вопросы и помочь вам понять больше.Многие из мелких партнеров в нем стали старыми драйверами.После их использования, все сказали, что очень довольны.Попробуй лодку и узнаешь 😀.