написать впереди
Объясните принцип реализации Redux самым простым способом? Грубо говоря, мои возможности ограничены, и я могу использовать только самый элементарный метод объяснения, для того, чтобы объяснить это более понятно, статья может быть отложена. Тем не менее, я считаю, что студенты, которые не очень хорошо знают Redux, обязательно что-то получат после прочтения статьи, которой я поделился сегодня!
Что такое Редукс?
Сегодня я не об этом, интересно, что такое ReduxНажмите на портал
Начинать
Прежде чем я начну, я хочу поговорить об общем шаблоне проектирования: шаблоне Observer. Сначала позвольте мне сказать
观察者模式Личное понимание: шаблон наблюдателя (публикация/подписка). Для студентов, которые хорошо разбираются в этом режиме, следующий код можно пропустить. Если вам все еще не ясно, вы можете попробовать ввести следующий код вручную! !
Шаблон наблюдателя
Шаблон наблюдателя, основанный на канале темы/события, объекты, которые хотят получать уведомления (называемые подписчиками), подписываются на пользовательские события. Прочтите тему и получите уведомление о том, как доставщик публикует событие темы. Так же, как пользователи подписываются на общедоступные учетные записи WeChat, пока они публикуются, пользователи могут получать новейший контент.
/**
* describe: 实现一个观察者模式
*/
let data = {
hero: '凤凰',
};
//用来储存 订阅者 的数组
let subscribers = [];
//订阅 添加订阅者 方法
const addSubscriber = function(fn) {
subscribers.push(fn)
}
//发布
const deliver = function(name) {
data.hero = name;
//当数据发生改变,调用(通知)所有方法(订阅者)
for(let i = 0; i<subscribers.length; i++){
const fn = subscribers[i]
fn()
}
}
//通过 addSubscriber 发起订阅
addSubscriber(() => {
console.log(data.hero)
})
//改变data,就会自动打印名称
deliver('发条')
deliver('狐狸')
deliver('卡牌')
Эта публикация и подписка сохраняет подписчиков (метод fn) через addSubscriber. Когда данные изменяются путем вызова доставки, он автоматически проходит через addSubscriber для выполнения внутри метода fn.
Зачем говорить об этой модели публикации-подписки? Поскольку вы понимаете этот паттерн, вы будете чувствовать себя более ясно, когда будете читать эту статью.
Начало работы с Redux
首先我们把上面那个发布订阅代码优化一下,顺便改一下命名,为什么要改命名?主要是紧跟 Redux 的步伐。让同学们更加眼熟。
let state = {hero: '凤凰'};
let subscribers = [];
//订阅 定义一个 subscribe
const subscribe = (fn) => {
subscribers.push(fn)
}
//发布
const dispatch = (name) => {
state.hero = name;
//当数据发生改变,调用(通知)所有方法(订阅者)
subscribers.forEach(fn=>fn())
}
//通过 subscribe 发起订阅
subscribe(() => {
console.log(state.hero)
})
//改变state状态,就会自动打印名称
//这里要注意的是,state状态不能直接去修改
dispatch('发条')
dispatch('狐狸')
dispatch('卡牌')
Теперь это изменение выглядит знакомым?Да, это идея, похожая на редукс, изменяющий состояние. Но публикации и подписки недостаточно, невозможно изменить состояние и нужно определить так много методов. Итак, мы инкапсулируем его.
метод creatStore
const creatStore = (initState) => {
let state = initState;
let subscribers = [];
//订阅 定义一个 subscribe
const subscribe = (fn) => {
subscribers.push(fn)
}
//发布
const dispatch = (currentState) => {
state = currentState;
//当数据发生改变,调用(通知)所有方法(订阅者)
subscribers.forEach(fn=>fn())
}
// 这里需要添加这个获取 state 的方法
const getState = () => {
return state;
}
return {
subscribe,
dispatch,
getState,
}
}
Это создает метод createStore. В этом нет ничего нового, просто перейдите в начальное состояние, а затем верните три метода подписки, отправки и getState. Вот новый метод getState, код очень прост для возврата состояния, чтобы получить состояние.
использование creatStore
Реализован createStore Попробуем как пользоваться, далее возьмем тот самый классический случай - счетчик попробовать
let initState = {
num: 0,
}
const store = creatStore(initState);
//订阅
store.subscribe(() => {
let state = store.getState()
console.log(state.num)
})
// +1
store.dispatch({
num: store.getState().num + 1
})
//-1
store.dispatch({
num: store.getState().num - 1
})
Это выглядит немного ближе к внешнему виду Redux. Но существует проблема. Если вы используете метод store.dispatch, будет больше проблем, если вы сделаете ошибку или передадите что-то еще посередине. Как следующее:
На самом деле, я думаю, что +1, +1, -1 должно быть 1 в конце (начальное число равно 0)! Но из-за неправильного написания следующее будет неправильным. И у него еще проблема в том, что он может дать новое состояние по желанию. Тогда это не кажется таким простым. Например следующее:
Поскольку num злонамеренно изменен на тип String, диспетчеризация используется позже.Поскольку num больше не имеет тип Number, печатается NaN, а это не то, что нам нужно. Поэтому мы должны преобразовать его, чтобы упростить отправку. Как это сделать? Давайте попросим менеджера помочь нам с этим, давайте назовем его редьюсером.
Почему он называется редуктором?
Я нашел следующее введение в редуктор на официальном сайте редуктора.
Конечно, этот перевод не работает.
Поискав официальный сайт китайского Redux, он сказал следующее:
Такая функция называется редуктором, потому что она имеет тот же тип, что и функция обратного вызова, переданная в Array.prototype.reduce(reducer, ?initialValue) . Очень важно поддерживать редуктор в чистоте. Никогда не выполняйте эти операции в редукторах.
Эй, этот перевод кажется намного яснее. Как сказал комментатор ниже, это вдохновлено методом сокращения в массиве, который является своего рода композицией операций. Итак, здесь я представлю сокращение.
что такое уменьшить
Нечего сказать, сразу к коду
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
/*该减速作用有四个参数:
*累加器(acc)
*当前价值(cur)
*当前指数(idx)
*源数组(src)
*您的reducer函数的返回值被分配给累加器,其值在整个阵列的每次迭代中被记住,并最终成为最终的单个结果值。
*/
Введение в конкретные параметры
callback
函数在数组中的每个元素上执行,有四个参数:
accumulator
累加器累加回调的返回值; 它是先前在回调调用中返回的累计值,或者initialValue,如果提供(参见下文)。
currentValue
当前元素在数组中处理。
currentIndex可选的
数组中正在处理的当前元素的索引。如果initialValue提供了an,则从索引0开始,否则从索引1开始
array可选的
该阵列reduce()被召唤。
initialValue可选的
用作第一次调用的第一个参数的值callback。如果未提供初始值,则将使用数组中的第一个元素。调用reduce()没有初始值的空数组是一个错误。
Этот метод сложнее для понимания, чем forEach, map, filter. См. также MDNArray.prototype.reduce()Подробное введение
Примечание: Прежде всего, я хотел бы поблагодарить нижеприведенного комментатора panda080 за его руководство.По его совету я пошел на официальный сайт Rudex, чтобы найти его снова. Изучая себя, я лучше понимаю редуктор и уменьшаюофициальный сайт редуктора
ps:理解完之后,其实个人觉得 reducer 这个命名从翻译过来的角度总觉得很怪异。可能英语有限,或许他有更加贴切的意思我还不知道。
что такое редуктор
В процессе моего исследования я думаю, что редьюсер — это менеджер (может быть, это не правильно), и тогда мы уведомляем менеджера каждый раз, когда хотим что-то сделать, и позволяем ему делать это в соответствии с тем, что мы говорим. Если мы случайно скажем что-то не так, то он этого не сделает. Просто следуйте за вещью по умолчанию. Редуктор Дэн Дэн Дэн Денг уже здесь! !
function reducer(state, action) {
//通过传进来的 action.type 让管理者去匹配要做的事情
switch (action.type){
case 'add':
return {
...state,
count: state.count + 1
}
case 'minus':
return {
...state,
count: state.count - 1
}
// 没有匹配到的方法 就返回默认的值
default:
return state;
}
}
С добавлением этого менеджера мы должны переписать предыдущий метод createStroe: поместить в него редюсер.
const creatStore = (reducer,initState) => {
let state = initState;
let subscribers = [];
//订阅 定义一个 subscribe
const subscribe = (fn) => {
subscribers.push(fn)
}
//发布
const dispatch = (action) => {
state = reducer(state,action);
subscribers.forEach(fn=>fn())
}
const getState = () => {
return state;
}
return {
subscribe,
dispatch,
getState,
}
}
Очень простая модификация, чтобы вам было легче увидеть модификацию и разницу, я перекодировал сравнение двух методов до и после, как показано ниже.
Хорошо, попробуем эффект от добавления менеджера в creatStore.
function reducer(state, action) {
//通过传进来的 action.type 让管理者去匹配要做的事情
switch (action.type){
case 'add':
return {
...state,
num: state.num + 1
}
case 'minus':
return {
...state,
num: state.num - 1
}
// 没有匹配到的方法 就返回默认的值
default:
return state;
}
}
let initState = {
num: 0,
}
const store = creatStore(reducer,initState);
//订阅
store.subscribe(() => {
let state = store.getState()
console.log(state.num)
})
Для того, чтобы результат был виден наглядно, рассылку (подписку) я вывожу прямо в консоль, как показано ниже:
Эффект очень хороший, у нас больше не будет NaN или других неописуемых проблем из-за опечаток. Теперь эта рассылка немного чище.
Мы просто даем ему тип и позволяем менеджеру решать, как изменить состояние для нас. Если вы случайно напишете ошибку, или дадите случайный тип и менеджер не сможет его сопоставить, то это действие будет недействительным, и будет возвращено наше собственное состояние по умолчанию.
Хорошо, это в основном то, что я увидел, когда впервые использовал Redux. В то время мне было очень трудно им пользоваться. В то время я едва понял эту демонстрацию счетчика и молча закрыл vs code.
Далее давайте улучшим этот редюсер и добавим к нему еще один метод. И на этот раз мы даем государству еще один
function reducer(state, action) {
//通过传进来的 action.type 让管理者去匹配要做的事情
switch (action.type){
case 'add':
return {
...state,
num: state.num + 1
}
case 'minus':
return {
...state,
num: state.num - 1
}
// 增加一个可以传参的方法,让他更加灵活
case 'changeNum':
return {
...state,
num: state.num + action.val
}
// 没有匹配到的方法 就返回默认的值
default:
return state;
}
}
let initState = {
num: 0,
}
const store = creatStore(reducer,initState);
//订阅
store.subscribe(() => {
let state = store.getState()
console.log(state.num)
})
Консоль снова использует новый метод:
Хорошо, это делает диспетчеризацию более гибкой?
Сейчас мы написали 3 метода в редьюсере, но в реальном проекте их должно быть много, поэтому их написание таким образом должно быть неблагоприятным для разработки и сопровождения. Так что этот вопрос остается для вас, чтобы подумать.
Подсказка: Redux тоже это знает, поэтому он предоставляет
combineReducersдля реализации этого шаблона. Это пример редьюсера более высокого порядка, который принимает объект разделенных функций редуктора и возвращает новую функцию редуктора.
Подумав об этом, вы можете обратиться кредукционная китайская документацияПредставляем combReducers
Суммировать
В проекте Redux есть много очень оригинальных методов, и многие места можно использовать для справки. В конце концов, это звезда 47W+ на github.
Сегодня я рассказал лишь о небольшой его части. Я также усердно учусь и надеюсь поделиться с вами еще большим количеством мнений и подробно обсудить их в будущем.
напиши в конце
Каждый из вышеперечисленных случаев и код размещены на github, и их можно открыть и использовать напрямую, поделившись со всеми.гитхаб-портал
Во всей статье, если есть какие-либо ошибки или неточности, обязательно исправьте их, спасибо!
Ссылаться на: