Search code examples
callbackscopebind

lost scope in callback, how to use bind effectively


in my case localesCollection within compareValue is having an old (not updated) value. State is not real-time. I assumed bind was here to save my day.

// Redux
let localesCollectionValues = useSelector((state: IStore) => state.localesStoreSlice.localesCollectionValues);

const compareValue = (fieldValue: any): void => {
    console.log('compareValue', fieldValue, localesCollectionValues);
}

const attachListeners = () => {
    console.log('attachListeners');
    Object.keys(sdk.entry.fields).forEach((field: string) => {
        const fieldRef: any = sdk.entry.fields[field];
        fieldRef.locales.forEach((localeKey: string) => {     
            fieldRef.getForLocale(localeKey).onValueChanged(compareValue.bind(this));
        });
    });
};

edit: is was coming from having the arrow function directly in the callback with the same issue as described above

edit2: the value of 'localesCollectionValues' is the value on the moment that the code get initialised and the handler gets set. After that its not updated and it just keeps hold of n old reference. Typical memory pointer / scope issue, in need of a direction to solve this.

fieldRef.getForLocale(localeKey).onValueChanged(() => {
   console.log(localesCollectionValues) // <- not real time, 
   // contains old value
});

Solution

  • In hindsight I just had to follow React Hooks directions for State Management, makes perfect sense:

    const [changedLocale, setChangedLocale] = useState('');
    
    useEffect(() => {
        console.log('changedLocale', changedLocale, localesCollection);
        // accurate, real-time
    }, [changedLocale, localesCollection]);
    
    const attachListeners = () => {
        Object.keys(sdk.entry.fields).forEach((field: string) => {
            sdk.entry.fields[field].locales.forEach((localeKey: string) => {
                const fieldRef: any = sdk.entry.fields[field];
                fieldRef.getForLocale(localeKey).onValueChanged(() => {
                    setChangedLocale(localeKey);
                });
            });
        });
    };