Unity - UIWidgets 7. Redux接入(二) 把Redux划分为不同数据模块

参考QF.UIWidgets
参考Unity官方示例 - ConnectAppCN

前面说过,当时没想明白一个问题,在reducer中每次返回一个new State(), 会造成极大浪费,没想到用什么办法来解决。
然后发现这些示例里面并没有每次创建一个新的State,只是直接修改了相应的值……那这样就简单多了。把Redux结构划分为不同数据模块,更方面管理。

在这里从头做一个简单的demo,包含两个页面:“homepage”,显示一条信息, “newpage”,显示一个计数

入口

// Main.cs
using System.Collections.Generic;
using Unity.UIWidgets;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.material;
using Unity.UIWidgets.Redux;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Redux.State;
using Redux.Reducer;
using Redux.View;

namespace Redux
{
    public class Main : UIWidgetsPanel
    {
        protected override void OnEnable()
        {
            base.OnEnable();
        }

        protected override Widget createWidget()
        {
            var widget = new MaterialApp(
                initialRoute: "/",
                routes: new Dictionary<string, WidgetBuilder>()
                {
                    { "/", context => new HomePage() },
                    { "new", context => new NewPage() },
                }
                );

            var store = new Store<AppState>(
                reducer: AppReducer.Reduce,
                initialState: new AppState()
                );

            return new StoreProvider<AppState>(
                child: widget,
                store: store
                );
        }
    }
}

View部分

// View/HomePage.cs
// 因为这里不是重点,NewPage略
using System;
using System.Collections.Generic;
using Unity.UIWidgets.materal;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.Redux;
using Unity.UIWidgets.widgets;
using UnityEngine;

namespace Redux.View
{
    public class HomePage : StatelessWidget
    {
        var widget = new Scaffold(
            appBar: new appBar(
                title: new Text("Home")
                ),
            body: new Center(
                children: new List<Widget>
                {
                    new StoreConnector<AppState, string>(
                        converter: (state) => state.globalState.message,
                        builder: (context1, text, dispatcher) => new Text(text)
                        ),
                    new StoreConnector<AppState, object>(
                        converter: (state) => null,
                        builder: (context2, _, dispatcher) => new RaisedButton(
                            child: new Text("当前时间"),
                            onPressed: () => {
                                dispatcher.dispatch(new Action.Global.SetMessageAction
                                {
                                    message = DateTime.Now.ToString()
                                });
                            }
                            )
                        ),
                    new RaisedButton(
                        child: new Text("打开新页面"),
                        onPressed: () => {
                            Navigator.pushNamed(context, "new");
                        }
                        )
                }
                )
            );

        return widget;
    }
}

State部分


// State/AppState.cs
namespace Redux.State
{
    public class AppState
    {
        public BagState bagState;
        public GlobalState globalState;

        public static AppState GetState()
        {
            AppState = new AppState
            {
                bagState = new BagState
                {
                    itemCount = 0;
                },
                globalState = new GlobalState
                {
                    message = "hello",
                },
            }
        }
    }
}

// State/BagState.cs
namespace Redux.State
{
    public class BagState
    {
        public int itemCount;
    }
}

// State/GlobalState.cs
namespace Redux.State
{
    public class GlobalState
    {
        public string message;
    }
}

Action部分

// Action/BagAction.cs
namespace Redux.Action
{
    public interface IBagAction {}
}

namespace Redux.Action.Bag
{
    public class AddCountAction : IBagAction
    {
        public int count;
    }

    public class RemoveCountAction : IBagAction
    {
        public int count;
    }
}

// Action/GlobalAction.cs
namespace Redux.Action
{
    public interface IGlobalAction {}
}

namespace Redux.Action.Global
{
    public class SetMessageAction : IGlobalAction
    {
        public string message;
    }
}

Reducer部分


// Reducer/AppReducer.cs
using Redux.Action;
using Redux.State;

namespace Redux.Reducer
{
    public static class AppReducer
    {
        public static AppState Reduce(AppState state, object action)
        {
            switch (action)
            {
                case IBagAction bagAction:
                    return BagReducer.Reduce(state, bagAction);
                case IGlobalAction globalAction:
                    return GlobalReducer.Reduce(state, globalAction);
                default:
                    return state;
            }
        }
    }
}

// Reducer/BagReducer.cs
using Redux.Action;
using Redux.Action.Bag;
using Redux.State;

namespace Redux.Reducer
{
    public static class BagReducer
    {
        public static AppState Reduce(AppState state, IBagAction action)
        {
            switch (action)
            {
                case AddCountAction addCountAction:
                    return OnAddCountAction(state, addCountAction);
                case RemoveCountAction removeCountAction:
                    return OnRemoveCountAction(state, removeCountAction);
                default:
                    return state;
            }
        }

        private static AppState OnAddCountAction(AppState state, AddCountAction action)
        {
            state.bagState.itemCount += action.count;
            return state;
        }

        private static AppState OnRemoveCountAction(AppState state, RemoveCountAction action)
        {
            state.bagState.itemCount -= action.count;
            return state;
        }
    }
}

// Reducer/GlobalReducer.cs
using Redux.Action;
using Redux.Action.Global;
using Redux.State;

namespace Redux.Reducer
{
    public static class GlobalReducer
    {
        public static AppState Reduce(AppState state, IGlobalAction action)
        {
            switch (action)
            {
                case SetMessageAction setMessageAction:
                    return OnSetMessageAction(state, setMessageAction);
                default:
                    return state;
            }
        }

        private static AppState OnSetMessageAction(AppState state, SetMessageAction action)
        {
            state.globalState.message = action.message;
            return state;
        }
    }
}

按这样的模式,redux部分(仅此部分)可以考虑写相应的代码生成工具了

原文地址:https://www.cnblogs.com/lunoctis/p/12372670.html

时间: 2024-10-03 14:45:37

Unity - UIWidgets 7. Redux接入(二) 把Redux划分为不同数据模块的相关文章

Unity里面的自动寻路(二)

接着我的 上一篇自动寻路文章,这一次我们就来学习一下与自动寻路有关的组件吧.Unity中与自动寻路相关的组件主要有两个:NavMeshAgent (  又称导航网格代理 ),Off Mesh Link( 分离网格链接 ).这两个组件的作用与使用范围是不同的,我们唯一可以确定的是我们必须烘焙地形,产生NavMesh(导航网格).因为导航网格决定我们的角色(带有导航网格代理的角色)活动的范围.NavMeshAgent组件需要附着寻路的角色身上,比如怪物,而OffMeshLink这个组件主要是用来构造

redux源码解析-redux的架构

redux很小的一个框架,是从flux演变过来的,尽管只有775行,但是它的功能很重要.react要应用于生成环境必须要用flux或者redux,redux是flux的进化产物,优于flux. 而且redux还很小.那么redux是怎么做到单项数据流和一些让人惊奇的特性的呢.我们来看一下他的源码,从而学一些东西. redux里面都是一个一个的模块,一共9个模块,都导出了一些redux的方法,比如这个9,一个匿名函数,然后导出他写的方法.9里面就这一个方法.英文注释也蛮清楚的,检测类对象的方法.

【Unity 3D】学习笔记二十八:unity工具类

unity为开发者提供了很多方便开发的工具,他们都是由系统封装的一些功能和方法.比如说:实现时间的time类,获取随机数的Random.Range( )方法等等. 时间类 time类,主要用来获取当前的系统时间. using UnityEngine; using System.Collections; public class Script_04_13 : MonoBehaviour { void OnGUI() { GUILayout.Label("当前游戏时间:" + Time.t

【Unity 3D】学习笔记二十六:unity游戏脚本(六)

在3D游戏世界中,任何一个游戏对象在创建的时候都会附带Transform(变换)组件,并且该组件是无法删除的,也不应该删除.在unity中,Transform面板一共有3个属性: Position  (位置) Rotation(旋转) Scale(缩放) 这三个值都是用来调整游戏对象在游戏界面中的位置,状态等相关参数. Position  (位置) 任何一个游戏对象的三维坐标都保存在Vector3容器中,该容器记录对象在X轴,Y轴,Z轴的坐标.一旦Vector33容器中的坐标发生变化,那么Sce

【Unity 3D】学习笔记二十九:游戏实例——简单小地图制作

任何的学习,光看不练是学不好的.所以这次就总结回顾下怎么制作MMROPG类游戏中的小地图.在MMROPG类游戏里,主角在游戏世界里走动时,一般在屏幕右上角都会有一个区域来显示当前游戏场景的小地图.主角在游戏世界里走动,小地图里代表着主角的小标记也会随之移动.那怎么实现咧? 首先需要确定两个贴图,第一个是右上角的小地图背景贴图,应该是从Y轴俯视向下截取主角所在的位置大地图.第二个就是主角的位置大贴图.在本例中,因为没有学习unity地图制作,所以地图用一个面对象代替,主角用立方体代替,使用GUI来

[Unity+Android]横版扫描二维码

终于解决了一个忧伤好久的问题,严重拖了项目进度,深感惭愧!一直被一系列的问题所困扰,然后又只能自己一个人摸索,也是一段辛酸忧伤史,现在小结一下上个月在做二维码的过程中所碰到的问题以及解决办法,现在庆幸终于解决好了,终于能将这个功能告一段落,一下小结也是分享一下Unity的某些"坑",让同行少走弯路,起码在二维码这方面应该会有所启迪,欣慰的是接下来几天终于可以做自己应该做的事情了! 效果图: 先小结一下碰到的问题: 1.Unity工程屏幕方向与Android工程屏幕方向要一致的问题 本来

【Unity 3D】学习笔记二十七:unity游戏脚本(七)

使用C#编写游戏脚本 在前面提到,unity支持三种语言编写脚本:js,C#,boo.入门的时候建议只用js,因为js比较简单易懂,语法也不是很严格.但后来晋级的时候推荐使用C#,因为它比较符合unity的编程思想,执行效率更高.下面总结下怎么使用C#编写脚本. 继承MonoBehaviour类 在unity中,任何一个脚本,包括上述三种语言都需要去继承MonoBehaviour这个类.为什么我们之前写JS代码的时候没有继承咧?因为在创建JS代码的时候,系统会将其类名与继承关系隐藏起来. 在pr

Unity - UIWidgets 4. 添加图标显示

Material Icon字体下载(github) 前面的返回按钮, 以及自己试验的一些Icon都不显示, 然后回去翻UIWidgets的README public class UIWidgetsExample : UIWidgetsPanel { protected override void OnEnable() { // if you want to use your own font or font icons. // FontManager.instance.addFont(Resou

redux入门二

在redux中用户的操作并不会直接导致view层的更新,而是view层发出actions通知出发store里的reducer从而来更新state. Action就像一个指挥者,告诉我们应该做哪些事,比如我要删除,reducer就会给我们提供'资源(就是上面说的数据)',真正的体力劳动者是reducer. 也就是说,action里面的每一种描述,比如新增啦,删除一个,删除全部啦,reducer都有一个对应的函数来处理数据.之后返回给你一个新的state. reducer 只是一个模式匹配的东西,真