React Reducer真的应该是一个纯函数吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Reducer真的应该是一个纯函数吗?相关的知识,希望对你有一定的参考价值。

据说useReducer中使用的reducer函数是纯函数。如果我没记错的话,“它的行为仅取决于其输入参数-因此使用相同的输入参数两次调用它会产生相同的结果。” (来自here)。并且(来自here):

减速器应:

  • 从不改变其参数

  • 从不产生副作用(没有API调用会改变任何东西)

  • 从不调用非纯函数,这些函数会根据输入以外的因素更改其输出(例如Date.now()或Math.random())>

我对此有两个问题:

  1. 任何人都可以解释为什么减速器必须是纯函数吗?例如如果在接收相同输入的同时返回两个不同的输出,怎么办?或者,如果有副作用怎么办?
  2. 请考虑以下示例代码:
    export function MyComponent(props: IPropTypes) 
        const reducer = (prevState, action) => 
            newState = deepClone(prevState);
            newState.count = newState.count + props.count;
            return newState;
        

        const [state, dispatch] = useReducer(reducer, ....);

        return (<div>
             ...
             </div>)
    

我对上述减速器不是很好的减速器,因为它也取决于道具(不是道具的输入)吗?为什么这是一件坏事?

答案

参考官方Redux documentation,编写具有纯功能的减速器会增加重用减速器的机会。

[我认为您可以通过将props.count用作函数的参数,并将其放入动作对象中,来使您的reducer变得纯净。我更喜欢制作payload字段。

这是我编写的有效代码:codesandbox,这就是我更改组件的方式:

const reducer = (state, action) => 
  switch(action.type)
    case "INCREMENT":
      return 
        ...state,
        count: state.count + action.payload
      ;
    default:
      return state;
  
;

export default (props) => 
  const [state, dispatch] = useReducer(reducer,  count: 0 );
  const increment = () => dispatch( type: "INCREMENT", payload: props.count );

  return (
    <div>
      <p>Current: state.count</p>
      <button onClick=increment>Increment</button>
    </div>
  );

另一答案

这样的reducer实际上是一个纯函数,但是由于其他原因是不好的:closures

export function MyComponent(props) 
  // Closure on props.count
  const reducer = (prevState, action) => 
    newState = deepClone(prevState);
    newState.count = newState.count + props.count;
    return newState;
  ;

  // The reducer assigned **ONCE** on initial render
  // for the entire component life (until unmount)
  const [state, dispatch] = useReducer(reducer, initialState);

  return <div>...</div>;

您可能希望在每个渲染器上减速器都会改变并动态地起作用,但是不会。如果在特定时刻props.count === 5总是降低newState.count = newState.count + 5;,这是非常意外的行为。

谁能解释为什么化简器必须是纯函数?例如如果在接收相同输入的同时返回两个不同的输出,怎么办?或者,如果有副作用怎么办?

如果reducer不是纯函数,则具有副作用,即更改某些其他数据(API调用)可能会导致在应用程序中某处出现stale数据。

这是因为化简器是异步的,您的化简器代码可能会完成并在屏幕上显示数据,但是实际上由于API调用并且陈旧了,此数据已经更改,但是您的应用程序没有意识到此更改,因此未获取任何渲染更改UI表示形式。

另一答案

这确实是一个不好的减速器,因为每次运行时,计数结果都会不同。精简器旨在获取数据并始终返回相同的结果。

想象一下,如果您在此组件中具有其他状态,它可能会以您未曾想到的方式触发reducer,并且计数将在整个渲染过程中发生变化并聚合。

以上是关于React Reducer真的应该是一个纯函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

offer 收割计划你知道为什么 reducer 最好是一个纯函数吗?

offer 收割计划你知道为什么 reducer 最好是一个纯函数吗?

offer 收割计划你知道为什么 reducer 最好是一个纯函数吗?

offer 收割计划你知道为什么 reducer 最好是一个纯函数吗?

[Redux/Mobx] 推荐在reducer中触发Action吗?为什么?

谈谈对redux的认识