V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
MinonHeart
V2EX  ›  问与答

前端状态的一个疑问

  •  
  •   MinonHeart · 249 天前 · 536 次点击
    这是一个创建于 249 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想要的效果

    调用 add 添加数据 -> 清空渲染器 -> 设置新的渲染器数据 -> 重新渲染

    非 add 调用不清空渲染器

    传统方式

    class Module {
        renderer = null; // 渲染器实例
    
        // 手动添加数据并渲染
        add(data) {
            this.renderer.clear(); // 清空渲染器(如果是手动添加数据则需要先清空渲染器)
            this.renderer.setData(data); // 更新渲染器数据
            this.renderer.render(); // 重新渲染新数据
        }
    }
    

    状态方式

    class ModuleState {
        needClear = false; // 标记需要清空渲染器
        @observable data = null; // 新的渲染数据
    
        // 手动添加数据
        add(data) {
        	this.needClear = true;
            this.data = data;
        }
    }
    
    // ModuleView 是异步的,ModuleState 中也拿不到 ModuleView
    class ModuleView {
        state = null; // ModuleState
        renderer = null; // 渲染器实例
    
        constructor() {
            // 当 ModuleState.data 发生变化时,自动渲染数据
            autorun(() => this.render(this.state.data))
        }
    
        render(data) {
            // 如果是手动添加数据则需要清空渲染器
            if (this.state.needClear) {
                this.renderer.clear();
                this.state.needClear = false;
            }
            this.renderer.setData(data); // 更新渲染数据
            this.renderer.render(); // 重新渲染新的数据
        }
    }
    

    问题

    在状态方式中,需要额外的一个标记来表示是否需要清空渲染器。

    1. 这个标记是全局可用的,是否合理?
      • 带来了调试上麻烦(实际情况这类标记会更多)
      • 在传统方式中,标记相当于在 add 函数内部,是私有的
    2. 是否有更好的方式来处理这个标记?
    2 条回复    2023-09-01 12:57:20 +08:00
    george2077
        1
    george2077  
       249 天前   ❤️ 1
    全局的话不好管理状态,调试不方便,封装性差
    解决方法局部状态管理:
    class ModuleView {
    state = null; // ModuleState
    renderer = null; // 渲染器实例
    needClear = false; // 私有标记

    constructor() {
    autorun(() => this.render(this.state.data))
    }

    render(data) {
    if (this.needClear) {
    this.renderer.clear();
    this.needClear = false;
    }
    this.renderer.setData(data);
    this.renderer.render();
    }

    add(data) {
    this.needClear = true;
    this.state.data = data;
    }
    }
    或者用回调或事件;
    class ModuleState {
    data = null;

    add(data, callback) {
    this.data = data;
    if (callback) {
    callback();
    }
    }
    }

    class ModuleView {
    state = null;
    renderer = null;

    constructor() {
    autorun(() => this.render(this.state.data))
    }

    render(data) {
    this.renderer.setData(data);
    this.renderer.render();
    }

    clearRenderer() {
    this.renderer.clear();
    }
    }

    // 使用
    const state = new ModuleState();
    const view = new ModuleView();

    state.add(someData, () => view.clearRenderer());
    MinonHeart
        2
    MinonHeart  
    OP
       249 天前
    @george2077 很合理。

    当前架构是 View 初始化后,任何地方都访问不到。按这样改得变更架构了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2714 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 15:59 · PVG 23:59 · LAX 08:59 · JFK 11:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.