尝试使用useState挂钩更新对象状态在RxJS主题订阅主体内部不起作用,但在其外部起作用。 (在第二个代码部分的注释中注释)

我收到的错误是:TypeError:eventMap.addEvent不是一个函数

我的目标是使用来自backpageMes​​sageSubject $的事件从EventMap调用addEvent,然后再将返回的数组从getNthEvent方法传递给子组件。

class EventMap {
     eventArrays;
     constructor() {
         this.eventArrays = new Map();
     }

    addEvent = (id, data) => {
        this.eventArrays.has(id)
            ? this.eventArrays.get(id).push(data)
            : this.eventArrays.set(id, [data]);
        return this.eventArrays;
    }

    getNthEvent = (n) => {
        const result = [];
        for (let key of this.eventArrays.keys()) {
            result.push(this.eventArrays.get(key)[n]);
        }
        return result;
    }
}


export default function MarbleDiagram(props) {
    const [eventMap, setEventMap] = useState(new EventMap());

    // Stream of events for this observable.
    const event$ = backpageMessageSubject$.pipe(
        filter(message => message.type === 'event'),
        map(message => message.event),
        filter(event => event.observable === props.observable)
    );

    useEffect(() => {
        const eventSubscription = event$.subscribe(event => {
            setEventMap(eventMap => eventMap.addEvent(1, 1)); // This does trigger error.
        });

        setEventMap(eventMap => eventMap.addEvent(1, 1)); // This does not trigger error.

        return () => {
            eventSubscription.unsubscribe();
        };
    }, []);
}


主题来源:

export const backpageMessageSubject$ = new Subject();

最佳答案

完成setEventMap(eventMap => eventMap.addEvent(1, 1))后,事件映射的状态是eventMap.addEvent的返回值,它不是EventMap实例。因此,稍后尝试使用它时,它会失败,因为您正在使用的(Map)没有addEvent

由于处于状态的项不能直接修改,因此您需要更新EventMap,使其返回具有添加事件的新地图实例,而不是按照以下方式更改现有地图:

class EventMap {
     eventArrays;
     constructor(eventArrays = new Map()) { // Note accepting a parameter
         this.eventArrays = eventArrays;
     }

    addEvent = (id, data) => {
        // Copy the current map, reusing the same arrays
        const eventArrays = new Map(this.eventArrays);
        // Get the current array for this `id`
        const current = eventArrays.get(id);
        if (!current) {
            // We don't have it, create a new one in the new map
            eventArrays.set(id, [data]);
        } else {
            // We have it, copy its contents to a new array and
            // add the new data to the end, storing it in the
            // new map
            eventArrays.set(id, [...current, data]);
        }
        // Create a new EventMap with those arrays and return it
        return new EventMap(eventArrays);
    }

    getNthEvent = (n) => {
        const result = [];
        for (let key of this.eventArrays.keys()) {
            result.push(this.eventArrays.get(key)[n]);
        }
        return result;
    }
}

10-05 23:34