【问题标题】:UseReducer modifying state multiple timesUseReducer 多次修改状态
【发布时间】:2021-01-24 03:46:38
【问题描述】:

我认为这是因为反模式的副作用。我从用户那里得到键盘输入并用它来修改状态。由于越来越复杂的状态,我最近从 useState 挂钩切换到 useReducer。它与 useState 挂钩效果很好。每个键盘输入都会多次打印到屏幕上。但是没有对状态进行键盘修改(不是来自事件处理程序的状态更改),不会显示多个渲染。

这是我的代码:

function TextBox() {
    const AppState = {
        /// Manages the state of the lines on the screen
        line: [[]],
        /// Line Index...
        lIdx: 0,
        /// Word Index...
        wIdx: 0,

        caretOn: false, timerOn: true, wordWrap: true,
    }

    const [state, dispatch] = useReducer(modifier, AppState)
    /*
     ...

    */
    return (
        <div id="txtbox" 
            tabIndex="0" 
            ref = {txtBoxRef}
            onKeyDown={(e) => dispatch({type: e.key})} >
                <Lines linesProp={linesParam} />
        </div>
    )
}

减速机:

export default function modifier(state, action)
{
    try {
        /// Stops the caret from blinking...
        const caretState = {
            caretOn: true, timerOn: false, wordWrap: true,
        }

        let values = {
                newLine: [], newLIdx: 0, newWIdx: 0
        }

        const set = val => ({...state, ...caretState, line: val.newLine, 
                lIdx: val.newLIdx, wIdx: val.newWIdx})

        switch (action.type)
        {
            case "Backspace":
             // Calls the Function that handles backspaces 
                // Declare new state values...
                values = Backspace({   /// Modify state values...
                    line: state.line, lIdx: state.lIdx, wIdx: state.wIdx
                })
                /// Update state values...
                return set(values)
            case " ":
            // Calls the fucntion that handles input from the spacebar
                /// Modify state values...
                values = spaceBar({line: state.line, lIdx: state.lIdx, wIdx: state.wIdx})
                /// Update state values...
                return set(values)
            /* .... */
           case "ArrowDown":
                if (state.lIdx < state.line.length)
                    return { ...state, ...caretState, lIdx: state.lIdx + 1}
                break;
            case "Enter":
                values = handleEnterKey({line: state.line, lIdx: state.lIdx, wIdx: state.wIdx})
                return set(values)
            case "text_wrap":
                values = handleWrap ({line: state.line, lIdx: state.lIdx, wIdx: state.wIdx,
                wordWrap: state.wordWrap})
                return {...state, ...values}
            case "hide-caret":
                return {...state, caretOn: state.caretOn=false};
            case "show-caret":
                return {...state, caretOn: state.caretOn=true};
            case "set-timer-on":
                return {...state, timerOn: state.timerOn=true};
            default:
            /// Modify state values...
                values = updateLine(action.type, state.line, state.lIdx, state.wIdx)
                /// Update state values...
                return set(values)
            }
            
    }
        catch (e) {
        console.info(e)
        console.log(state)
    }
}

【问题讨论】:

  • 除了show|hide-caret 改变先前状态的动作(即caretOn: state.caretOn = falsecaretOn: state.caretOn = true 我没有看到任何其他明显的突变/副作用,但我们看不到任何你的实用函数正在做什么。你能包括BackspacespaceBarhandleEnterKeyhandleWrapupdateLine等......函数吗?
  • @DrewReese,这里是源文件:TextBoxReducerUtilities

标签: reactjs


【解决方案1】:

我没有技术知识,但似乎 react 根本不希望 &lt;React.StrictMode&gt; 有任何副作用。如果您有非原始数据类型。 useReducer 不会深入检查并查看它是同一个对象。避免改变对象、深拷贝并返回更新的对象。这类似于 setState。 useState 可以更好地处理变异对象。

修复:我将所有方法重写为不可变。

【讨论】:

    猜你喜欢
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2021-01-17
    相关资源
    最近更新 更多