Научите, как использовать Redux в небольших программах

внешний интерфейс Vue.js React.js Redux

Использование управления состоянием 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а такжеactionstypesИспользуется для определения того, что мы хотим вызвать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Там действительно много дыр~