为什么事件处理函数无法获取更新后的状态对象值?

问题描述 投票:0回答:1

这是我的代码:

App.js:

import './App.css';
import { useAlarmClock } from "./useAlarmClock";
export default function App() {
  const[action,data]=useAlarmClock();
  let start=()=>{
    action.start();
  }
  return (
    <div className="App">
      <button onClick={start}>Start Alarm Clock</button>
    </div>
  );
}

使用AlarmClock.js

import { useReducer } from "react";
import AlarmClock from './AlarmClock';
let reducer = (state, action) => {
    let result = { ...state };
    console.log(action);
    switch (action.type) {
        case "init":
            result = { "alarmClock": action.alarmClock }
            break;
        default: break;    
    }
    return result
}

export function useAlarmClock() {
    const [itemList, updateItemList] = useReducer(reducer, {});
    let start = () => {
        let alarmClock = new AlarmClock();
        alarmClock.on("connectionTimeout", () => {
            console.log(itemList);
        })
        alarmClock.start();
        updateItemList({ "type": "init", alarmClock })
    }
    return [{
        start: start
    }, {
        itemList
    }];
}

闹钟.js

export default class AlarmClock {
    constructor() {
        let connectionTimeoutHandler;

        /*=====================================================================*/
        /*        To configure handler for varies event                        */
        /*=====================================================================*/
        this.on = (eventType, param) => {
            switch (eventType) {
                case "connectionTimeout":
                    connectionTimeoutHandler = param;
                    break;
                default: break;
            }
        };
        this.start = () => {
            setTimeout(() => {
                connectionTimeoutHandler();
            }, 5000);
        }
    }
}

我期望以下函数的输出:

alarmClock.on("connectionTimeout", () => {
        console.log(itemList);
    })

应该是:

{
  "alarmClock":{}
}

然而实际结果如下:

{}

所以,我不知道为什么console.log输出不包含alarmClock对象。

javascript reactjs react-hooks
1个回答
0
投票

在每次渲染时,由于不变性,都会为 itemList 创建一个新对象,但您只能链接到“connectionTimeout”回调中的 itemList 的第一个实例。您可以使用 ref hook 访问所需版本的 itemList,因此您需要像这样执行 smtn:

使用AlarmClock.js

import { useReducer } from "react";
import AlarmClock from './AlarmClock';
let reducer = (state, action) => {
    let result = { ...state };
    console.log(action);
    switch (action.type) {
        case "init":
            result = { "alarmClock": action.alarmClock }
            break;
        default: break;    
    }
    return result
}

export function useAlarmClock() {
    const [itemList, updateItemList] = useReducer(reducer, {});
    const itemListRef = useRef(itemList);
    itemListRef.current = itemList;
    let start = () => {
        let alarmClock = new AlarmClock();
        alarmClock.on("connectionTimeout", () => {
            console.log(itemListRef.current);
        })
        alarmClock.start();
        updateItemList({ "type": "init", alarmClock })
    }
    return [{
        start: start
    }, {
        itemList
    }];
}

UPD:这是工作示例:

const {useReducer, useEffect, useRef} = React;

function App() {
  const[action,data]=useAlarmClock();
  let start=()=>{
    action.start();
  }
  return (
    <div className="App">
      <button onClick={start}>Start Alarm Clock</button>
    </div>
  );
}

let reducer = (state, action) => {
    let result = { ...state };
    console.log(action);
    switch (action.type) {
        case "init":
            result = { "alarmClock": action.alarmClock }
            break;
        default: break;    
    }
    return result
}

function useAlarmClock() {
    const [itemList, updateItemList] = useReducer(reducer, {});
    const itemListRef = React.useRef(itemList);
    itemListRef.current = itemList;
    let start = () => {
        let alarmClock = new AlarmClock();
        alarmClock.on("connectionTimeout", () => {
            console.log(itemListRef.current);
        })
        alarmClock.start();
        updateItemList({ "type": "init", alarmClock })
    }
    return [{
        start: start
    }, {
        itemList
    }];
}
class AlarmClock {
    constructor() {
        let connectionTimeoutHandler;

        /*=====================================================================*/
        /*        To configure handler for varies event                        */
        /*=====================================================================*/
        this.on = (eventType, param) => {
            switch (eventType) {
                case "connectionTimeout":
                    connectionTimeoutHandler = param;
                    break;
                default: break;
            }
        };
        this.start = () => {
            setTimeout(() => {
                connectionTimeoutHandler();
            }, 5000);
        }
    }
}


ReactDOM.render(<App />,
document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

© www.soinside.com 2019 - 2024. All rights reserved.