首页 > 解决方案 > React reducer 必须是纯函数吗?

问题描述

我写了一个 UI 元素作为一个函数组件,它使用 React 的userReducer钩子,它似乎运行没有错误。

useReducer引用我写的一个函数(想象地称为reducer):

  const [state, dispatch] = React.useReducer(reducer, inputData,
    (inputData) => initialState(inputData));

statereducer函数输入输出的数据;并且有一些“托管”的 UI 元素取决于state...

  return (
    <div>
      <div>
        {state.elements.map(getElement)}
      </div>
      <ShowHints hints={state.hints} inputValue={state.inputValue} />
    </div>
  );

……这很正常。

我担心的是该reducer功能不纯。

副作用是有一个<input>元素的状态由以下之一控制:

const inputRef = React.createRef<HTMLInputElement>();

<input>控件只是半托管的,如下所示:

<input type="text" ref={inputRef} onKeyDown={handleKeyDown} onChange={handleChange}

onKeyDown和事件是分派给reducer的onChange动作(这很好),但是reducer将HTMLInputElement实例(即inputRef.current值)作为输入参数传递,reducer设置它的属性HTMLInputElement来改变它的状态——而不是<input>存在一个完全托管的组件,其内容由 reducer 输出的状态定义。

<input>元素不是完全管理的原因是我需要控制选择范围(即startend),<input>而不仅仅是它的文本值。

问题:

(我认为@Fyodor 下面的回答回答了第二个问题,我仍然不确定第一个问题)。


什么决定了要在 HTML 元素上设置的值?传入的使用信息是否包含逻辑?

组件的设计和源代码显示在这里,而且相当长。

它是一个复杂的“组件”,它使用几个元素来实现——几个<div>s、几个<span>s、一些可点击<svg>的 s 和<input>元素。

给出了减速器,作为它的输入参数:

几个事件处理程序或动作中的两个是onKeyDown和的onChange事件,<input>因此<input>当有一个事件改变<input>.

标签: reactjstypescriptreact-hookspure-function

解决方案


从技术上讲,reducer 可能会产生不同的副作用。我认为这不是一个好的做法,至少由于关注点分离不好(预计reducer 只会根据动作产生新状态,而不是改变其他东西)。(很抱歉提出我自己的意见,似乎使用了副作用useReducer,就像这里一样)。同样在 Redux 中,所有副作用都转移到了action creators中。

对于您的具体问题,我可能会建议将inputRef突变移动到单独useEffect的钩子,这又取决于如下状态

useEffect (() => {
    inputRef.currect // do work with inputRef
}, [state]); // make dependent from state

这是制作依赖表格的示例useEffectstate

您还可以移动useEffect自定义挂钩以使代码可重用,如下所示(未经测试,用作提示)

function mutateRef (inputRef: React.RefObject<HTMLInputElement>, state: /* type of state */) {
    useEffect (() => {
        inputRef.currect // do work with inputRef
    }, [state, inputRef]);
}

推荐阅读