【问题标题】:Mithril filtering list of components秘银过滤组件列表
【发布时间】:2016-06-23 10:22:30
【问题描述】:

我在尝试使用 mithril.js 过滤数据列表时遇到了问题。

我有两个组件:一个表单和一个 inputWrapper。

  • 表单显示一个包含多个输入字段的表单,每个字段都有一个值。
  • 该表单还具有允许过滤数据的搜索输入。

在表单视图中直接使用m('input', { value: ...} ) 时,过滤效果很好。

当使用包含输入和与其值耦合的m.prop 的组件时,一切都会出错。 在表格中我们有类似的东西:m.component( inputWrapper, { value: ... }) 尝试过滤此列表时,视图会呈现错误的组件。

查看this codepen 以获得更清晰的图片。

我的猜测是,秘银差异引擎存储了一组缓存组件并呈现这些组件,而不是在每次重绘时实例化新组件。 然而,我还没有找到解决这个问题的方法。请帮忙。

【问题讨论】:

    标签: components filtering mithril.js


    【解决方案1】:

    我不得不稍微重构你的代码才能遵循逻辑,但设法让它工作。

    缓存问题与控制器有关:在重绘时,如果给定类型的组件呈现在与上一次绘制中相同类型的组件相同的位置 - 并且组件没有区分键 - 然后假设您要检索以前的控制器。对于您的组件,控制器存储视图使用的输入(而不是视图直接从其自己的args 输入中读取它)。

    解决此问题的最简单方法是简单地摆脱控制器并直接读取输入,因为如果输入应该始终是新鲜的,它就没有任何理想的用途。

    // ---------------------------------
    //     component with an input
    // ---------------------------------
    const inputWrapper = {
    	view : ( ctrl, args ) =>    
    		m('input[type=text]', args )
    }
    
    // ---------------------------------
    //    component that filters list
    // ---------------------------------
    m.mount( document.body, {
    	controller : function( attrs ) {
    		const filterTerm = m.prop( '(?:)' )
    		
    		return { 
    			filterTerm, 
    			filterFunc : word => {
    				const term = filterTerm()
    				
    				if ( _.isString( term ) && _.isString( word ) )
    					return word.search( new RegExp( term, 'i' ) ) > -1
    			}, 
    			someData : [ "long", "list", "of", "meaningful", "data", "really", "cool", "stuff"]
    		}
    	},
    	
    	view : ( { filterTerm, filterFunc, someData }, attrs ) =>
    		m('form',
    			m('p',
    				m('input[type=text]', {
    					oninput     : m.withAttr( 'value', filterTerm ),
    					placeholder : 'filter data'
    				})
    			),
    			
    			m('p',
    				m('ul',
    					someData
    						.reduce( ( acc, val ) =>
    							( ( filterTerm() && filterTerm() == '/(?:)/' ) || filterFunc(val) )
    							? acc.concat( val )
    							: acc, 
    						[] 
    						)
    						.map( value => 
    							m('li',
    								m('input',      { value } ),
    								m(inputWrapper, { value } )
    							)
    						)
    				)
    			)
    		)
    } )
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.5/mithril.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>

    但是,此修复揭示了其他问题:因为生成列表(和组件)的数据是在每次绘制时动态创建的,输入将绑定到的数据结构在每次重绘时被简单地处理掉,当从父组件中的 reduce 和 map 函数生成一个新数组。

    该问题的解决方案是在接收数据的父控制器中执行归约,以便可以在下一次绘制中检索。

    我对代码所做的其他小调整:

    • 视图中虚拟 DOM 子项的数组括号是不必要的(出于个人喜好,我删除了很多标点符号:)。
    • 您在 let 赋值中执行的解构可以在函数参数签名中执行,从而减少冗长。
    • 删除这些赋值允许箭头函数表达式的“隐式返回”形式,这样可以更轻松地查看视图输出的结构,同时删除要考虑的变量数量。
    • 使用const 而不是let 可以清楚地表明分配给引用的值不能更改,这样可以更轻松地找到代码可能在哪里发生意外情况。
    • 将reduce 表达式的回调减少为三元可以清楚地表明只有1 个逻辑条件和2 个可能的结果,并且concat 允许您在单个表达式中生成一个新结构(而不​​是pushing 和那么returning.

    【讨论】:

      【解决方案2】:

      在又一轮挖掘秘银的文档之后,我来这里回答我自己的问题。

      如果我在初始化组件时提供了 key

      m.component( InputWrapper, { key: 'distinguishingKey', value: ... } )

      一切都会好起来的。

      感谢巴尼的提示:

      ...并且组件没有区分键 - ...

      感谢 Leo Horie 提供了出色的文档。 (如果我几周前读到这...) http://mithril.js.org/mithril.component.html#data-driven-component-identity

      【讨论】:

        猜你喜欢
        • 2017-01-20
        • 2017-07-04
        • 2017-09-24
        • 1970-01-01
        • 1970-01-01
        • 2013-05-03
        • 1970-01-01
        • 2019-08-03
        相关资源
        最近更新 更多