我写了一个 UI 元素作为函数组件,它使用 React 的 userReducer
钩子(Hook),它似乎运行没有错误。
useReducer
引用我写的一个函数(想象中称为 reducer
):
const [state, dispatch] = React.useReducer(reducer, inputData,
(inputData) => initialState(inputData));
有state
由reducer函数输入和输出的数据;并且有依赖于 state
的“托管”UI 元素, 像...
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
和 onChange
事件是发送给 reducer 的 Action (这很好)但是 reducer 被传递给了 HTMLInputElement
实例(即 inputRef.current
值)作为输入参数,reducer 设置该 HTMLInputElement
的属性改变它的状态——而不是 <input>
作为一个完全托管的组件,其内容由 reducer 输出的状态定义。
<input>
的原因element isn't fully-managed 是我需要控制 start
内的选择范围(即 end
和 <input>
)而不仅仅是它的文本值。
问题:
- reducer 函数以这种方式不纯是否可以(例如,尽管有问题或值得注意但没有错误)?
- 它只依赖于它的输入参数,因此是可重复的
- 但它会改变某些东西(即
inputRef.current
属性)并返回新的state
值(value)
- reducer 有没有其他方法来控制
start
和end
<input type="text">
的属性元素,例如一种定义<input>
的方法元素使得它的start
和end
值由他控制state
由 reducer 返回?
(我认为 @Fyodor's answer below 回答了第二个问题,我仍然不确定第一个问题)。
什么决定了要在 HTML 元素上设置的值?使用信息是否传入或包含逻辑?
组件的设计和源代码是shown here ,而且很长。
这是一个复杂的“组件”,使用多个元素实现——两个 <div>
s,几个<span>
s,一些可点击的 <svg>
s 和 <input>
元素。
reducer 是给定的,作为它的输入参数:
- 之前的“状态”
- 当前
<input>
实例(它可以从中读取<input>
的当前状态) - 事件处理程序创建的“ Action ”
几个事件处理程序或操作中的两个是 onKeyDown
和 onChange
<input>
的事件所以 <input>
的当前状态当有一个事件改变了 <input>
的状态时,它被传递给 reducer .
最佳答案
从技术上讲,reducer 可能会产生不同的副作用。我不认为这是一个好的做法,至少是因为关注点分离不好(预计 reducer 只根据 Action 产生新状态,而不是改变其他东西)。 (很抱歉提出我自己的意见,似乎使用了 useReducer
中的副作用,例如 here )。同样在 Redux 中,所有副作用都移到了 action creators。 .
对于您的具体问题,我可能会建议将 inputRef
突变移动到单独的 useEffect
Hook ,这反过来又取决于如下状态
useEffect (() => {
inputRef.currect // do work with inputRef
}, [state]); // make dependent from state
这里是 sample使 useEffect
依赖于 state
您还可以将 useEffect
移动到 custom hook使代码像下面一样可重用(未经测试,用作提示)
function mutateRef (inputRef: React.RefObject<HTMLInputElement>, state: /* type of state */) {
useEffect (() => {
inputRef.currect // do work with inputRef
}, [state, inputRef]);
}
关于reactjs - React reducer 必须是纯函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57142137/