2017-08-03 33 views
1

首先,这里是我的HOC:如何正确记忆mapDispatchToProps?

export default function connectField({ 
     nameProp = 'name', 
     valueProp = 'value', 
     dispatchProp = 'dispatch' 
    }: ConnectOptions) { 

    return compose(
     getContext(contextTypes), 
     connect((state, ownProps) => { 
      const path = [namespace,...getPath(ownProps),...toPath(ownProps[nameProp])]; 
      const value = getOr('', path, state); 
      return { 
       [valueProp]: value 
      }; 
     }, (dispatch,ownProps) => { // <----------- mapDispatchToProps 
      const path = [...getPath(ownProps),...toPath(ownProps[nameProp])]; 

      return { 
       [dispatchProp]: value => dispatch({type: ActionTypes.Change, payload: {path, value}}) 
      }; 

     }, (stateProps, dispatchProps, {[FIELD_PATH]: _, ...ownProps}) => { 
      return {...stateProps, ...dispatchProps, ...ownProps}; 
     }, { 
      areMergedPropsEqual: (a,b) => { 
       let eq = shallowEqual(a,b); 
       console.log('areMergedPropsEqual',a,b,eq); 
       return eq; 
      }, 
     }), 
     withContext(contextTypes, props => { 
      return {[FIELD_PATH]: [...getPath(props), props[nameProp]]}; 
     }), 
    ); 
} 

在中间有我的mapDispatchToProps。这导致areMergedPropsEqual每次都会返回false,因为它每次都会创建一个新的动作创建器。

我无法弄清楚如何memoize的该位:

value => dispatch({type: ActionTypes.Change, payload: {path, value}}) 

,这样我每次得到相同的功能实例。

关于“per-instance memoization”,这是我想要的,但我无法完全理解我应该在这里做的正面或反面的一些注意事项in the docs


要清楚,我知道如何记忆一个函数。但是,我不希望使用具有无限历史的大缓存。这是不必要的内存消耗。我只需要像how reselect does it那样的缓存大小1。问题在于我不能直接在connectField内创建“选择器”,因为它仍然会创建一个共享实例 - 即所有“连接的字段”将共享相同的缓存,并且它们将相互覆盖,从而否定好处。它必须是每个组件实例这是特定于React-Redux的connect方法。它有一个语法,以便您可以在正确的位置创建选择器,并且每个实例只会运行一次。我只是在解密API时遇到问题 - 他们是否期望一个函数返回一个返回对象的函数?或者是一个带有名称作为键和函数作为值的对象?那个函数返回什么?即文档不清楚mapDispatchToProps选项所接受的所有不同变化。

+0

更多的相关信息@KyleRichardson更紧密地阅读'mapDispatchToProps'。它需要一个“对象*或*函数”。然后,如果函数需要一个或两个参数,它会再次执行一些不同的操作。然后在“高级场景”下,它说该函数可以*返回一个函数。所以呃...我想我想用一个参数传递一个函数并返回一个返回对象的函数。没关系,我会捣鼓它,直到我弄明白为止。 – mpen

+1

我很抱歉没有找到你想要的东西。我现在了解这个问题,这是一个非常有趣的问题。仍然在想它......如果你想出一个解决方案,请你更新一下,以便我可以查看想法:) –

回答

0

如果你已经有lodash,你有一个memoize函数,允许将任何函数转换成memoized函数。这个memoized函数将计算给定参数的返回值,然后总是返回相同的返回值,每个参数都提供相同的参数。

您可以使用它像这样的例子:

import { memoize } from 'lodash' 

const makeChangeDispatcher = memoize((dispatch, path) => 
    value => dispatch({type: ActionTypes.Change, payload: {path, value}}) 
) 

... 

    (dispatch,ownProps) => { // <----------- mapDispatchToProps 
     const path = [...getPath(ownProps),...toPath(ownProps[nameProp])]; 

     return { 
      [dispatchProp]: makeChangeDispatcher(dispatch, path) 
     }; 

    } 

... 

你可以看到在lodash documentation of memoize

+0

我认为你错过了这一点。我遇到的部分是每个实例memoization *。您创建了一个具有无限历史记录的单个全局memoized函数。它可能有效,但我的目标是避免由于道具变化而重新渲染。为此,我只需要1的历史记录大小,但它必须是每个实例。对不起,我应该更清楚一点。 – mpen

+0

是的,越来越多的历史可能是一个潜在的问题,但这是给你一个基于调度功能(总是相同)和取决于你的组件道具的路径memoized功能。所以你会有实例的功能。正是通过路径价值泥潭。所以具有相同路径的两个组件共享相同的功能(这不是问题)。这里有什么问题?我错过了点^^ –

+0

问题是缓存不需要随着道具的变化而增长。我所要做的就是避免由于道具变化而重新渲染。如果道具没有改变,我想回到相同的派遣功能。如果改变了,那么可能会返回一个新的调度函数。为此,我只需要1的缓存大小。 – mpen