Предыдущая статьяМы написали Redux вручную, но чистый Redux — это просто конечный автомат, в нем нет представления пользовательского интерфейса, поэтому, как правило, когда мы его используем, мы будем использовать библиотеку пользовательского интерфейса, такую как использование Redux в React.React-Redux
эта библиотека. Что делает эта библиотека, так это связывает конечный автомат Redux и рендеринг пользовательского интерфейса React, когда выdispatch action
Изменятьstate
Время, автоматически обновит страницу. Эта статья также начинается с основ использования его, чтобы написатьReact-Redux
Затем замените официальную NPM библиотеку и сохраните функциональность последовательными.
Весь код в этой статье был загружен на GitHub, вы можете снять его и поиграть:GitHub.com/Денис — см....
Основное использование
Следующий простой пример представляет собой счетчик, и эффект выглядит следующим образом:
Чтобы реализовать эту функцию, сначала нам нужно добавить в проектreact-redux
библиотеку, затем используйте предоставленнуюProvider
Весь пакетReact
Корневой компонент приложения:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import store from './store'
import App from './App';
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
Приведенный выше код может видеть, что мы возвращаемProvider
предоставил параметрstore
, это параметр ReduxcreateStore
Сгенерированоstore
, нам нужно вызвать этот метод, а затем вернутьstore
Биография:
import { createStore } from 'redux';
import reducer from './reducer';
let store = createStore(reducer);
export default store;
в приведенном выше кодеcreateStore
Параметр представляет собойreducer
, поэтому мы также пишемreducer
:
const initState = {
count: 0
};
function reducer(state = initState, action) {
switch (action.type) {
case 'INCREMENT':
return {...state, count: state.count + 1};
case 'DECREMENT':
return {...state, count: state.count - 1};
case 'RESET':
return {...state, count: 0};
default:
return state;
}
}
export default reducer;
здесьreduce
будет начальныйstate
,внутриcount
да0
Пока он может справиться с тремяaction
,Эти триaction
В соответствии с тремя кнопками пользовательского интерфейса вы можетеstate
Счетчик внутри увеличивается, уменьшается и сбрасывается. Вот мы на самом делеReact-Redux
доступ иRedux
Организация данных фактически завершена. Если вы хотите использовать ее позжеRedux
Если данные внутри, просто используйтеconnect
API будет соответствоватьstate
И метод подключается к компоненту, например, нашему компоненту-счетчику нужноcount
Это состояние и плюс один, минус один, сбросить эти триaction
,мы используемconnect
Подключите его так:
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement, reset } from './actions';
function Counter(props) {
const {
count,
incrementHandler,
decrementHandler,
resetHandler
} = props;
return (
<>
<h3>Count: {count}</h3>
<button onClick={incrementHandler}>计数+1</button>
<button onClick={decrementHandler}>计数-1</button>
<button onClick={resetHandler}>重置</button>
</>
);
}
const mapStateToProps = (state) => {
return {
count: state.count
}
}
const mapDispatchToProps = (dispatch) => {
return {
incrementHandler: () => dispatch(increment()),
decrementHandler: () => dispatch(decrement()),
resetHandler: () => dispatch(reset()),
}
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter)
Вы можете увидеть вышеуказанный кодconnect
является функцией высшего порядка, первый порядок которой получаетmapStateToProps
а такжеmapDispatchToProps
Два параметра, оба из которых являются функциями.mapStateToProps
который можно настроитьstate
подключенные к текущему компоненту, эти пользовательскиеstate
можно передать в компонентеprops
получать.mapDispatchToProps
метод пройдет вdispatch
функцию, мы можем настроить некоторые методы, эти методы можно вызватьdispatch
идтиdispatch action
, что вызываетstate
update, эти пользовательские методы также можно передать черезprops
получать,connect
Полученный параметр второго порядка является компонентом, мы можем предположить, что функция этой функции заключается в настройке предыдущегоstate
Метод и внедряется внутрь сборки, а новый компонент возвращается к внешнему вызову, поэтомуconnect
Фактически, это также компонент более высокого порядка.
Здесь мы суммируем, какие API мы использовали.Эти API являются целями, которые мы напишем позже:
Provider
: компонент, используемый для обертывания корневого компонента, роль которого заключается в внедренииRedux
изstore
.
createStore
:Redux
используется для созданияstore
основной метод,У нас есть другая статья, переданная рукописными.
connect
: используется для преобразованияstate
а такжеdispatch
Внедрить в требуемый компонент и вернуть новый компонент, который на самом деле является компонентом более высокого порядка.
такReact-Redux
На самом деле в основе лежат два API, и оба они являются компонентами, и их функции очень похожи, они оба вводят параметры в компоненты.Provider
вводится в корневой компонентstore
,connect
вводится в нужный компонентstate
а такжеdispatch
.
Прежде чем писать, давайте подумаем, почемуReact-Redux
Для разработки этих двух API, если нет двух API, используйте толькоRedux
Могу я? Конечно, это возможно! На самом деле мы используемRedux
Цель состоит не в том, чтобы использовать его для сохранения состояния всего приложения, а использовать его только для каждой операции.dispatch action
Обновлять состояние, а потом UI автоматически обновляется? Затем я начинаю с корневого компонента и помещаюstore
Можно ли передать это? Когда каждому подкомпоненту нужно прочитать состояние, используйте его напрямуюstore.getState()
Вот и все, просто обновите статусstore.dispatch
, это действительно может достичь цели. Однако если так написано, то при наличии множества вложенных уровней подкомпонентов каждый уровень нужно вручную передавать вstore
, что некрасиво и громоздко разрабатывать, а если новый одноклассник забудет сдатьstore
, после чего последовал ряд ошибок. Так что лучше иметь что-то, что можетstore
Глобально внедрить дерево компонентов, не требуя слой за слоем, какprops
пройти, это вещьProvider
! И если каждый компонент зависит независимоRedux
уничтожитReact
Направление потока данных, о котором мы поговорим позже.
Контекстный API React
React фактически предоставляет API для глобального внедрения переменных, который является контекстным API. Если теперь у меня есть требование передать конфигурацию цвета текста всем нашим компонентам, наша цветовая конфигурация находится в компоненте верхнего уровня.При изменении цвета все следующие компоненты будут автоматически применять этот цвет. Затем мы можем внедрить эту конфигурацию с помощью контекстного API:
Используйте имяReact.createContext
создать контекст
// 我们使用一个单独的文件来调用createContext
// 因为这个返回值会被Provider和Consumer在不同的地方引用
import React from 'react';
const TestContext = React.createContext();
export default TestContext;
использоватьContext.Provider
обернуть корневой компонент
Создал контекст, если мы хотим передать переменные некоторым компонентам, нам нужно добавить в их корневые компонентыTestContext.Provider
, затем поместите переменную какvalue
параметр, переданныйTestContext.Provider
:
import TestContext from './TestContext';
const setting = {
color: '#d89151'
}
ReactDOM.render(
<TestContext.Provider value={setting}>
<App />
</TestContext.Provider>,
document.getElementById('root')
);
использоватьContext.Consumer
получить параметры
Выше мы используемContext.Provider
Параметры передаются, так чтоContext.Provider
Все подкомпоненты пакета могут получить эту переменную, но вам нужно использовать эту переменную, когда вы ее получитеContext.Consumer
пакеты, такие как наши предыдущиеCounter
Компонент может получить этот цвет, просто верните егоJSX
использоватьContext.Consumer
Просто завершите это:
// 注意要引入同一个Context
import TestContext from './TestContext';
// ... 中间省略n行代码 ...
// 返回的JSX用Context.Consumer包裹起来
// 注意Context.Consumer里面是一个方法,这个方法就可以访问到context参数
// 这里的context也就是前面Provider传进来的setting,我们可以拿到上面的color变量
return (
<TestContext.Consumer>
{context =>
<>
<h3 style={{color:context.color}}>Count: {count}</h3>
<button onClick={incrementHandler}>计数+1</button>
<button onClick={decrementHandler}>计数-1</button>
<button onClick={resetHandler}>重置</button>
</>
}
</TestContext.Consumer>
);
В приведенном выше коде мы передаемcontext
Пройдя глобальную настройку, вы увидите, что цвет нашего текста изменился:
использоватьuseContext
получить параметры
кроме вышеперечисленногоContext.Consumer
Может быть использован для полученияcontext
Параметры, а также новая версия ReactuseContext
Этот хук может получать параметры контекста, что проще в использовании, например, приведенный выше код можно написать так:
const context = useContext(TestContext);
return (
<>
<h3 style={{color:context.color}}>Count: {count}</h3>
<button onClick={incrementHandler}>计数+1</button>
<button onClick={decrementHandler}>计数-1</button>
<button onClick={resetHandler}>重置</button>
</>
);
Таким образом, мы можем использоватьcontext api
пройтиredux store
, теперь мы также можем предположитьReact-Redux
изProvider
на самом деле это упаковкаContext.Provider
, а переданный параметрredux store
,а такжеReact-Redux
изconnect
HOC на самом деле упаковкаContext.Consumer
илиuseContext
. Мы можем сделать это самиReact-Redux
.
почеркProvider
сказано вышеProvider
использовалcontext api
, поэтому мы сначала строимcontext
файл для экспортаcontext
:
// Context.js
import React from 'react';
const ReactReduxContext = React.createContext();
export default ReactReduxContext;
Этот файл очень простой, создайте новыйcontext
Просто экспортируйте его снова.Соответствующий исходный код находится здесь.
тогда поставь этоcontext
обратиться к нашемуProvider
Внутри компонента:
import React from 'react';
import ReactReduxContext from './Context';
function Provider(props) {
const {store, children} = props;
// 这是要传递的context
const contextValue = { store };
// 返回ReactReduxContext包裹的组件,传入contextValue
// 里面的内容就直接是children,我们不动他
return (
<ReactReduxContext.Provider value={contextValue}>
{children}
</ReactReduxContext.Provider>
)
}
Provider
Код компонента не сложный, напрямую передайте входящийstore
помещатьcontext
, а затем визуализировать напрямуюchildren
Просто хорошо,Соответствующий исходный код находится здесь.
почеркconnect
основные навыки
фактическиconnect
Это самая сложная часть React-Redux. У него сложные функции и множество факторов, которые необходимо учитывать. Чтобы понять это, нам нужно смотреть на него слой за слоем. Во-первых, мы реализуем базовую функцию, которая имеет только базовые функции.connect
.
import React, { useContext } from 'react';
import ReactReduxContext from './Context';
// 第一层函数接收mapStateToProps和mapDispatchToProps
function connect(mapStateToProps, mapDispatchToProps) {
// 第二层函数是个高阶组件,里面获取context
// 然后执行mapStateToProps和mapDispatchToProps
// 再将这个结果组合用户的参数作为最终参数渲染WrappedComponent
// WrappedComponent就是我们使用connext包裹的自己的组件
return function connectHOC(WrappedComponent) {
function ConnectFunction(props) {
// 复制一份props到wrapperProps
const { ...wrapperProps } = props;
// 获取context的值
const context = useContext(ReactReduxContext);
const { store } = context; // 解构出store
const state = store.getState(); // 拿到state
// 执行mapStateToProps和mapDispatchToProps
const stateProps = mapStateToProps(state);
const dispatchProps = mapDispatchToProps(store.dispatch);
// 组装最终的props
const actualChildProps = Object.assign({}, stateProps, dispatchProps, wrapperProps);
// 渲染WrappedComponent
return <WrappedComponent {...actualChildProps}></WrappedComponent>
}
return ConnectFunction;
}
}
export default connect;
запустить обновление
используйте вышеуказанноеProvider
а такжеconnect
заменить официальноеreact-redux
На самом деле страница может быть отрендерена, но нажатие на кнопку не будет реагировать, потому что хотя мы и проходимdispatch
измененныйstore
серединаstate
, но это изменение не привело к обновлению нашего компонента. Как упоминалось в статье Redux ранее, вы можете использоватьstore.subscribe
контролироватьstate
изменения и выполнить обратный вызов, обратный вызов, который нам нужно зарегистрировать здесь, чтобы проверить, что мы, наконец, даемWrappedComponent
изprops
Нет изменений, если есть изменения, перерисоватьConnectFunction
, так что здесь нам нужно решить две задачи:
- когда мы
state
Когда изменение проверено, финал даетConnectFunction
параметры изменились?- Если этот параметр изменится, нам нужно перерендерить
ConnectFunction
Проверить изменения параметров
Чтобы проверить изменение параметров, нам нужно знать параметры последнего рендеринга и параметры локального рендера, а затем сравнить их. Для того, чтобы узнать параметры последнего рендера, мы можем напрямуюConnectFunction
внутри использованиеuseRef
Запишите параметры последнего рендера:
// 记录上次渲染参数
const lastChildProps = useRef();
useLayoutEffect(() => {
lastChildProps.current = actualChildProps;
}, []);
УведомлениеlastChildProps.current
назначается после первого рендеринга и должен использоватьсяuseLayoutEffect
Обеспечить синхронное выполнение сразу после рендеринга.
Поскольку мы обнаруживаем изменения параметров, которые необходимо пересчитатьactualChildProps
, логика расчета на самом деле такая же, мы извлекаем эту логику расчета и делаем ее отдельным методомchildPropsSelector
:
function childPropsSelector(store, wrapperProps) {
const state = store.getState(); // 拿到state
// 执行mapStateToProps和mapDispatchToProps
const stateProps = mapStateToProps(state);
const dispatchProps = mapDispatchToProps(store.dispatch);
return Object.assign({}, stateProps, dispatchProps, wrapperProps);
}
Тогда зарегистрируйтесьstore
Обратный вызов используется для определения того, изменился ли параметр.Если он изменился, текущий компонент принудительно обновляется, и два объекта сравниваются, чтобы увидеть, равны ли они.React-Redux
внутри используетсяshallowEqual
, то есть поверхностное сравнение, то есть только один слой сравнения, если выmapStateToProps
Возвращаются несколько слоев структур, например:
{
stateA: {
value: 1
}
}
ты изменил этоstateA.value
не вызовет повторный рендеринг,React-Redux
Я думаю, что этот дизайн сделан из соображений производительности.Если это глубокое сравнение, такое как рекурсивное сравнение, это пустая трата производительности, а если есть циклические ссылки, это может вызвать бесконечный цикл. Использование неглубокого сравнения требует, чтобы пользователи следовали этой парадигме, не переходили в многоуровневую структуру,Это также объясняется в официальной документации. Здесь мы напрямую копируем его поверхностное сравнение:
// shallowEqual.js
function is(x, y) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
return x !== x && y !== y
}
}
export default function shallowEqual(objA, objB) {
if (is(objA, objB)) return true
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false
}
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
if (keysA.length !== keysB.length) return false
for (let i = 0; i < keysA.length; i++) {
if (
!Object.prototype.hasOwnProperty.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])
) {
return false
}
}
return true
}
Обнаружение изменений параметров в обратном вызове:
// 注册回调
store.subscribe(() => {
const newChildProps = childPropsSelector(store, wrapperProps);
// 如果参数变了,记录新的值到lastChildProps上
// 并且强制更新当前组件
if(!shallowEqual(newChildProps, lastChildProps.current)) {
lastChildProps.current = newChildProps;
// 需要一个API来强制更新当前组件
}
});
Принудительное обновление
Существует более одного способа принудительно обновить текущий компонент, если вы используетеClass
компонент, вы можете напрямуюthis.setState({})
, старая версияReact-Redux
Вот что он делает. Но новая версияReact-Redux
Переписано с помощью хука, тогда мы можем использовать React при условииuseReducer
илиuseState
крюк,React-Redux
исходный код используетсяuseReducer
, чтобы быть последовательным с ним, я также используюuseReducer
:
function storeStateUpdatesReducer(count) {
return count + 1;
}
// ConnectFunction里面
function ConnectFunction(props) {
// ... 前面省略n行代码 ...
// 使用useReducer触发强制更新
const [
,
forceComponentUpdateDispatch
] = useReducer(storeStateUpdatesReducer, 0);
// 注册回调
store.subscribe(() => {
const newChildProps = childPropsSelector(store, wrapperProps);
if(!shallowEqual(newChildProps, lastChildProps.current)) {
lastChildProps.current = newChildProps;
forceComponentUpdateDispatch();
}
});
// ... 后面省略n行代码 ...
}
connect
Этот код в основном соответствует исходному кодуconnectAdvanced
Основной принцип и структура этого класса такие же, как и у нас, но он более гибкий и поддерживает передачу пользователями пользовательскихchildPropsSelector
и объединитьstateProps, dispatchProps, wrapperProps
Методы. Заинтересованные друзья могут пойти и посмотреть его исходный код:GitHub.com/Горячее цинкование это/Горячее…
Здесь мы можем использовать наши собственныеReact-Redux
Заменена официальная, так же поддерживается функция счетчика. Но я хочу поговорить оReact-Redux
Как обеспечить порядок обновления компонентов, потому что много кода в исходном коде имеет дело с этим.
Гарантированный порядок обновления компонентов
перед нашимCounter
Использование компонентовconnect
связаныredux store
, если под ним есть подкомпонент, который также связан сredux store
, мы должны учитывать порядок выполнения их обратных вызовов. Мы знаем, что React — это односторонний поток данных, и параметры передаются от родительских компонентов к дочерним.Redux
, даже если и родительский, и дочерний компоненты ссылаются на одну и ту же переменнуюcount
, но дочерний компонент может совершенно не брать этот параметр у родительского компонента, а напрямую уRedux
Возьми и он сломаетсяReact
Исходный поток данных. существует父->子
В этом одностороннем потоке данных, если одна из их общедоступных переменных изменяется, сначала должен быть обновлен родительский компонент, а затем параметры передаются дочернему компоненту, а затем обновляются, но вRedux
, данные становятсяRedux -> 父,Redux -> 子
,父
а также子
полностью основано наRedux
Данные обновляются независимо, и процесс обновления сначала родительского, а затем дочернего не может быть полностью гарантирован. такReact-Redux
Потребовалось много усилий, чтобы вручную гарантировать этот порядок обновлений,React-Redux
Схема, гарантирующая этот порядок обновления, находится вredux store
Кроме того, создайте отдельный класс слушателяSubscription
:
Subscription
ответственность за всеstate
изменить обратный вызов- если в данный момент подключен
redux
Компонент является первым соединениемredux
компонент, то есть он связанredux
корневая составляющая егоstate
Обратный вызов регистрируется непосредственно наredux store
; также создайте новыйSubscription
примерsubscription
пройти черезcontext
переходил к детям.- если в данный момент подключен
redux
Компоненты не связаныredux
Корневой компонент , то есть на нем есть компоненты, зарегистрированные дляredux store
, то он может получить указанный выше проходcontext
переданныйsubscription
, переменная в исходном коде называетсяparentSub
, обратный вызов обновления текущего компонента регистрируется вparentSub
начальство. Также создайте новыйSubscription
экземпляр, альтернативаcontext
Вверхsubscription
, продолжить загрузку, то есть обратный вызов его подкомпонента будет зарегистрирован на текущийsubscription
начальство.- когда
state
изменен, корневой компонент регистрируется наredux store
Обратный вызов выше выполнит обновление корневого компонента, а корневой компонент должен вручную выполнить обратный вызов подкомпонента.Выполнение обратного вызова подкомпонента вызовет обновление подкомпонента, а затем подкомпонент выполнится сам.subscription
Обратный вызов, зарегистрированный выше, инициирует обновление внучатого компонента, а внучатый компонент вызывает и регистрирует сам себя.subscription
на обратный звонок. . . Это позволяет начать с корневого компонента и обновлять подкомпоненты слой за слоем, гарантируя, что父->子
Такая последовательность обновления.
Subscription
Добрый
Итак, давайте создадим новыйSubscription
Добрый:
export default class Subscription {
constructor(store, parentSub) {
this.store = store
this.parentSub = parentSub
this.listeners = []; // 源码listeners是用链表实现的,我这里简单处理,直接数组了
this.handleChangeWrapper = this.handleChangeWrapper.bind(this)
}
// 子组件注册回调到Subscription上
addNestedSub(listener) {
this.listeners.push(listener)
}
// 执行子组件的回调
notifyNestedSubs() {
const length = this.listeners.length;
for(let i = 0; i < length; i++) {
const callback = this.listeners[i];
callback();
}
}
// 回调函数的包装
handleChangeWrapper() {
if (this.onStateChange) {
this.onStateChange()
}
}
// 注册回调的函数
// 如果parentSub有值,就将回调注册到parentSub上
// 如果parentSub没值,那当前组件就是根组件,回调注册到redux store上
trySubscribe() {
this.parentSub
? this.parentSub.addNestedSub(this.handleChangeWrapper)
: this.store.subscribe(this.handleChangeWrapper)
}
}
Subscription
Соответствующий исходный код находится здесь.
МодернизацияProvider
а потом реализовали сами до насReact-Redux
Внутри наш корневой компонент всегдаProvider
,такProvider
необходимо создать экземплярSubscription
и положиcontext
на, и каждый разstate
При обновлении необходимо вручную вызвать обратный вызов подкомпонента, модификация кода выглядит следующим образом:
import React, { useMemo, useEffect } from 'react';
import ReactReduxContext from './Context';
import Subscription from './Subscription';
function Provider(props) {
const {store, children} = props;
// 这是要传递的context
// 里面放入store和subscription实例
const contextValue = useMemo(() => {
const subscription = new Subscription(store)
// 注册回调为通知子组件,这样就可以开始层级通知了
subscription.onStateChange = subscription.notifyNestedSubs
return {
store,
subscription
}
}, [store])
// 拿到之前的state值
const previousState = useMemo(() => store.getState(), [store])
// 每次contextValue或者previousState变化的时候
// 用notifyNestedSubs通知子组件
useEffect(() => {
const { subscription } = contextValue;
subscription.trySubscribe()
if (previousState !== store.getState()) {
subscription.notifyNestedSubs()
}
}, [contextValue, previousState])
// 返回ReactReduxContext包裹的组件,传入contextValue
// 里面的内容就直接是children,我们不动他
return (
<ReactReduxContext.Provider value={contextValue}>
{children}
</ReactReduxContext.Provider>
)
}
export default Provider;
Модернизацияconnect
имеютSubscription
Добрый,connect
не могу зарегистрироваться напрямуюstore
вместо этого он должен быть зарегистрирован в родительскомsubscription
В приведенном выше примере при обновлении помимо самого обновления он также уведомляет подкомпоненты об обновлении. При рендеринге обернутого компонента его нельзя рендерить напрямую, но его следует использовать снова.Context.Provider
Под пакетом вставьте модифицированныйcontextValue
,этоcontextValue
внутриsubscription
следует заменить на свой. Модифицированный код выглядит следующим образом:
import React, { useContext, useRef, useLayoutEffect, useReducer } from 'react';
import ReactReduxContext from './Context';
import shallowEqual from './shallowEqual';
import Subscription from './Subscription';
function storeStateUpdatesReducer(count) {
return count + 1;
}
function connect(
mapStateToProps = () => {},
mapDispatchToProps = () => {}
) {
function childPropsSelector(store, wrapperProps) {
const state = store.getState(); // 拿到state
// 执行mapStateToProps和mapDispatchToProps
const stateProps = mapStateToProps(state);
const dispatchProps = mapDispatchToProps(store.dispatch);
return Object.assign({}, stateProps, dispatchProps, wrapperProps);
}
return function connectHOC(WrappedComponent) {
function ConnectFunction(props) {
const { ...wrapperProps } = props;
const contextValue = useContext(ReactReduxContext);
const { store, subscription: parentSub } = contextValue; // 解构出store和parentSub
const actualChildProps = childPropsSelector(store, wrapperProps);
const lastChildProps = useRef();
useLayoutEffect(() => {
lastChildProps.current = actualChildProps;
}, [actualChildProps]);
const [
,
forceComponentUpdateDispatch
] = useReducer(storeStateUpdatesReducer, 0)
// 新建一个subscription实例
const subscription = new Subscription(store, parentSub);
// state回调抽出来成为一个方法
const checkForUpdates = () => {
const newChildProps = childPropsSelector(store, wrapperProps);
// 如果参数变了,记录新的值到lastChildProps上
// 并且强制更新当前组件
if(!shallowEqual(newChildProps, lastChildProps.current)) {
lastChildProps.current = newChildProps;
// 需要一个API来强制更新当前组件
forceComponentUpdateDispatch();
// 然后通知子级更新
subscription.notifyNestedSubs();
}
};
// 使用subscription注册回调
subscription.onStateChange = checkForUpdates;
subscription.trySubscribe();
// 修改传给子级的context
// 将subscription替换为自己的
const overriddenContextValue = {
...contextValue,
subscription
}
// 渲染WrappedComponent
// 再次使用ReactReduxContext包裹,传入修改过的context
return (
<ReactReduxContext.Provider value={overriddenContextValue}>
<WrappedComponent {...actualChildProps} />
</ReactReduxContext.Provider>
)
}
return ConnectFunction;
}
}
export default connect;
сюда нашReact-Redux
Готово, эффект от запуска такой же, как и у официального, полный код выложен на GitHub:GitHub.com/Денис — см....
Ниже мы резюмируемReact-Redux
основной принцип.
Суммировать
-
React-Redux
подключенReact
а такжеRedux
библиотека, при использованииReact
а такжеRedux
API. -
React-Redux
в основном используетсяReact
изcontext api
пройтиRedux
изstore
. -
Provider
это получитьRedux store
и поместите его вcontext
передай. -
connect
Роль изRedux store
Выберите необходимые свойства для передачи компоненту-оболочке. -
connect
Он сам рассудит, нужно ли его обновлять, и нужна ли основа для суждения.state
изменилось. -
connect
При оценке того, есть ли изменение, используется поверхностное сравнение, то есть сравнивается только один слой, поэтому вmapStateToProps
а такжеmapDispatchToProps
Не возвращайте многоуровневые вложенные объекты. - Чтобы решить независимые зависимости родительских компонентов и дочерних компонентов
Redux
,сломанныйReact
из父级->子级
процесс обновления,React-Redux
использоватьSubscription
Сам класс управляет процессом уведомления. - подключаться только к
Redux
Компоненты верхнего уровня будут зарегистрированы непосредственно вRedux store
, другие дочерние компоненты будут зарегистрированы в ближайшем родительском компонентеsubscription
на экземпляре. - При уведомлении он, в свою очередь, уведомляет свои собственные подкомпоненты от корневого компонента.Когда подкомпонент получает уведомление, он сначала обновляет себя, а затем уведомляет свои собственные подкомпоненты.
использованная литература
Официальная документация:react-redux.js.org/
Исходный код GitHub:GitHub.com/Горячее цинкование это/Горячее…
В конце статьи спасибо, что потратили свое драгоценное время на чтение этой статьи. Если эта статья немного поможет вам или вдохновит, пожалуйста, не скупитесь на лайки и звезды GitHub. Ваша поддержка является движущей силой для автор продолжать творить.
Добро пожаловать, чтобы обратить внимание на мой общедоступный номербольшой фронт атакиПолучите высококачественные оригиналы впервые~
Цикл статей "Передовые передовые знания":nuggets.capable/post/684490…
Адрес GitHub с исходным кодом из серии статей «Advanced Front-end Knowledge»:GitHub.com/Денис — см....