Использование управления состоянием Redux в мини-программах WeChat
предисловие
Некоторое время назад я разрабатывал небольшие программы, используя официальный фреймворк.wepy, если вы не знаете одноклассников, вы можете пойти к немуОфициальный сайтОбратитесь к соответствующим материалам, чтобы узнать; я должен сказать, что этот фреймворк действительно намного удобнее, чем традиционный режим разработки небольших программ. Его синтаксис очень похож на синтаксис Vue. Он может осуществлять разработку компонентов, а также настраивать и поддерживать код позади. ..но! ! Ям у этого фреймворка не мало и при разработке всегда будут странные проблемы.Наступайте сами,чтобы прогрессировать~~
Столько ерунды, кхм, вышеописанное не в фокусе нашего обсуждения, сегодня наш фокус - использование в небольших программахReduxдля государственного управления,ReduxЭто контейнер для внешнего управления состоянием.Для создания масштабных приложений очень удобно управлять общими данными и состоянием в нем.Я научилсяReactОдноклассники, знакомые с ним, не должны быть незнакомы с ним.посмотри;
wepyСам фреймворк поддерживаетReduxДа, когда мы строим проект, нужно ли устанавливатьReduxвыберитеyЭто хорошо, зависимости установятся автоматически.После запуска проекта смотрите официальную.demoЭто можно сделать, но в официальной документации об этом не упоминается. После того, как я попробовал это сам, я понял, как это использовать, и я быстро поделился этим с вами~
Внимание, сосредоточьтесь на следующем~
Реализация
Запустите наш проект и обнаружите, что официальный сайт дал нам некоторыеReduxМетод использования, по сути, в основном помещается вstoreПапка ниже, давайте посмотрим сейчас ~
step1
входной файлindex.js, который в основном является инициализациейRedux, вpromiseMiddlewareЭто промежуточное ПО, удобное для дальнейшегоactionВыполнять асинхронную обработку~reducersЯвляетсячистая функция, для принятияActionи текущийStateВ качестве аргумента возвращает новыйState~
import { createStore , applyMiddleware } from 'redux'
import promiseMiddleware from 'redux-promise'
import reducer from './reducers'
const Store = createStore(
reducer ,
applyMiddleware(promiseMiddleware)
)
export default configStore => Store
step2
Остальные три папкиtypes reducersа такжеactions,вtypesИспользуется для определения того, что мы хотим вызватьactionимя, что означаетactionимя, здесь я определяюcounterа такжеlistдваtypes, содержание следующее:
counter.js
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'
export const ASYNC_INCREMENT = 'ASYNC_INCREMENT'
list.js
export const ADD = 'ADD'
export const REMOVE = 'REMOVE'
наконец прошлоtypesфайл входа в папкуindex.jsразоблачить их~
export * from './counter'
export * from './list'
step3
reducersВ файле хранятся наши чистые функции по изменению нашего состояния, а также у него есть файл входаindex.js, определяемый следующим образом:
import { combineReducers } from 'redux'
import counter from './counter'
import list from './list'
export default combineReducers({
counter ,
list
})
Первое местоcounterа такжеlistвводятся отдельно, черезreduxОпределенныйcombineReducersфункция, которая преобразует всеreducersСоединившись в единое целое, нам удобно им потом управлять!
Такcounterа такжеlistсоответствующийreducerКакие они? Давайте посмотрим непосредственно на код:
counter.js
import { handleActions } from 'redux-actions'
import { INCREMENT , DECREMENT , ASYNC_INCREMENT } from '../types/counter'
const defaultState = {
num: 0 ,
asyncNum: 0
}
export default handleActions({
[INCREMENT](state){
return{
...state,
num : state.num + 1
}
},
[DECREMENT](state){
return{
...state,
num : state.num - 1
}
},
[ASYNC_INCREMENT](state, action){
return {
...state ,
asyncNum : state.asyncNum + action.payload
}
}
},defaultState)
Давайте представимcounter.jsвнутриreducer, впервые представленhandleActionsметод созданияactions, это будет несколько связанныхreducerТоже пишется слитно, в плане последующего сопровождения, а так же удобно для последующего прохожденияdispatchпризвать их изменитьсяstateСостояние внутри, оно в основном получает два параметра, первый параметр — это большой объект, который хранит несколькоreducer, второй параметр - время инициализацииstateЗначение состояния , следовательно, мы определяем в началеdefaultState ;
Далее заглянем внутрьreducer, соответственно определитьINCREMENT,DECREMENTа такжеASYNC_INCREMENTтриreducer, первые два относительно просты, соответственноstateвнутриnumЗначение складывается и вычитается, а последнее передается черезaction.payloadценность дляasyncNumЗначение асинхронной операции, как это сделать, мы увидим позже~
list.jsопределено вreducerКак и в предыдущем случае, я не буду вводить их по одному, просто вставлю код напрямую~
list.js
import { handleActions } from 'redux-actions'
import { ADD , REMOVE } from '../types/list'
const defaultState = [
{
title : '吃饭' ,
text : '今天我要吃火锅'
},
{
title : '工作' ,
text : '今天我要学习Redux'
}
]
export default handleActions({
[ADD]( state , action ){
state.push(action.payload)
return [...state]
},
[REMOVE]( state , action ){
state.splice( action.payload , 1 );
return [ ...state ]
}
},defaultState)
step4
Мы, наконец, подошли к этому моменту, вот, вы недалеко от ваших ожиданий, осталось только одноactionsфайл, без исключения, входной файлindex.jsследующим образом:
index.js
export * from './counter'
Это очень просто, достаточно поставить необходимоеactionПросто экспортируйте его~
я только что определилcounterизaction, то есть для асинхронных данных только чтоasyncNumготов~
counter.js
import { ASYNC_INCREMENT } from '../types/counter'
import { createAction } from 'redux-actions'
export const asyncInc = createAction(ASYNC_INCREMENT,()=>{
return new Promise(resolve=>{
setTimeout(()=>{
resolve(1)
},1000)
})
})
здесь сreducerЧтобы различать внутри, вот ряд обработки данных, мы проходимcreateActionСоздаватьaction, метод имеет два основных параметра, первый параметрtypeвыражатьactionтип второго параметраpayloadCreatorЯвляетсяfunction, обработать и вернуть требуемыйpayload; если отсутствует, будет использоваться метод по умолчанию. Вот и задерживаемся1sвернуть1;
хорошо, пока вы в основном завершилиreduxконтейнер~
Теперь пришло время показать, как его использовать~
step5
мы создаемindex.wpyфайл, здесь я вставляю код напрямую, а затем медленно анализирую его~
код показывает, как показано ниже:
<template lang="wxml">
<view class="container">
<text>同步{{ num }}</text>
<text>异步{{ asyncNum }}</text>
<button @tap="increment" type="primary">加一</button>
<button @tap="decrement" type="primary">减一</button>
<button @tap="asyncIncrement" type="primary">异步加一</button>
<button @tap="addList">添加</button>
<view class="box">
<view class="item" wx:for-items="{{ todoList }}" wx:key="index">
<view class="title">{{ item.title }}</view>
<view class="content">{{ item.text }}</view>
<button type="primary" class="delete" @tap="delete({{index}})">删除</button>
</view>
</view>
</view>
</template>
<script>
import wepy from 'wepy'
import { connect } from 'wepy-redux'
import { INCREMENT , DECREMENT } from '../store/types/counter'
import { asyncInc } from '../store/actions'
@connect({
num(state){
return state.counter.num;
},
asyncNum(state){
return state.counter.asyncNum;
}
},{
increment : INCREMENT ,
decrement : DECREMENT ,
asyncIncrement : asyncInc
})
export default class Index extends wepy.page {
components = {}
computed = {
todoList(){
return wepy.$store.getState().list;
}
}
methods = {
delete(index){
wepy.$store.dispatch({ type : 'REMOVE' , payload : index })
},
addList(){
wepy.$store.dispatch({ type : 'ADD' , payload : {
title : '学习' ,
text : '好好学习'
}})
}
}
onLoad () {
console.log(wepy.$store.getState())
}
}
</script>
<style lang="less">
text{
display: block;
text-align: center;
margin: 10px auto;
}
button{
width: 90%;
display: block;
margin: 10px auto;
}
.item{
display: flex;
align-items: center;
text-align: center;
padding: 0 15px;
.title{
font-size: 14px;
line-height: 20px;
margin: 10px auto;
}
.content{
font-size: 15px;
flex: 1;
}
.delete{
width: 70px;
height: 40px;
line-height: 40px;
}
}
</style>
Неудивительно, что после запуска интерфейс вашего апплета будет таким, как показано ниже — Ugly~
Немного поискав, я нашел корыто, оно очень классное, есть дрова~
хорошо~ Давайте посмотрим, как выполняется приведенный выше код~
С точки зрения структуры стиля, мы не будем здесь ее обсуждать, мы в основном рассмотримjsчасть которогоimport { INCREMENT , DECREMENT } from '../store/types/counter'а такжеimport { asyncInc } from '../store/actions'соответственно изcounterа такжеactionsэкспортировать желаемоеaction
Давайте сосредоточимся наwepy-reduxвведен вconnect,этоconnectОчень важно, это мост между компонентами и состояниями, основное использование@connect(states, actions) ~
-
states: посещениеstateЗначение на , может быть массивом или объектом, если это объект, он содержитK-Vправильно,VМожет быть функцией или строкой, если это строка, то она будет получена по умолчаниюstate[V], в противном случае используется возвращаемое значение; и если это массив (элементы в массиве могут быть только строками), он считается тем жеK-Vструктура объекта.statesв конечном итоге будет прикреплен к компонентуcomputedзначение атрибута. -
actions: Можно передавать только объекты, объектK-Vструктура, еслиVЕсли это строка, она будет напрямуюdistatchСледующая структура:// args 就是调用传入参数 { type: val, // 修正一般情况下的参数 一般支持只传一个参数 // 如果真的是多个参数的话 那么 payload 就是参数组成的数组 payload: args.length > 1 ? args : args[0] }если функция
fn, будуdispatch(val.apply(store, args)), иначе напрямуюdispatch(V)
Здесь мы определяемплюс один,минус одина также异步加一операции отображаются непосредственно наINCREMENT,DECREMENT,asyncInc, что эквивалентно непосредственноdispacthСоответствующая операция по изменению данных~
Вы должны увидеть эффект сейчас~
Конечно, мы также можем вручную вызвать контейнерdispatchметод изменения данных, нашДобавить ка такжеудалятьВот что он делает,
Нажмите кнопку «Добавить», мы прямоdispatchв спискеADD action,следующим образом:
wepy.$store.dispatch({ type : 'ADD' , payload : {
title : '学习' ,
text : '好好学习'
}})
удалятьчто-то, простоdispatchсписокREMOVE action, передайте индекс для удаления:
delete(index){
wepy.$store.dispatch({ type : 'REMOVE' , payload : index })
},
Если не веришь, посмотри~
Вы закончили~
Эпилог
хорошо, до сих пор мы пытались придумать маленький трюк. Оглядываясь назад, мы обнаружили, что это было не так уж сложно. Я научилсяReactМои одноклассники должны быть знакомы с этим, давайте изучим скорость света~ Но что касается меня, я действительно новичок, и я надеюсь дать такому новому другу, как я, роль в привлечении новых идей.Если что-то не так в письме , Пожалуйста, также критикуйте топор~
код, который я разместил дляgithubНа, если вам это нужно, вы можете скачать его самостоятельно~
пс:wepyТам действительно много дыр~