Repository: plotly/dash
File: dash/dash-renderer/src/actions/callbacks.ts (TypeScript)

Code before:
    let progressDefault: any;
    let moreArgs = additionalArgs;

    if (running) {
        dispatch(sideUpdate(running.running, payload));
        runningOff = running.runningOff;
    }

    const fetchCallback = () => {
        const headers = getCSRFHeader() as any;
        let url = `${urlBase(config)}_dash-update-component`;
        let new_body = body;

        const addArg = (name: string, value: string) => {
            let delim = '?';
            if (url.includes('?')) {
                delim = '&';
            }
            url = `${url}${delim}${name}=${value}`;
        };
        if (cacheKey || job) {
            if (cacheKey) addArg('cacheKey', cacheKey);
            if (job) addArg('job', job);

            // clear inputs as background callback doesnt need inputs, just verify for context
            const tmp_body = JSON.parse(new_body);
            for (let i = 0; i < tmp_body.inputs.length; i++) {
                tmp_body.inputs[i]['value'] = null;
            }
            for (let i = 0; i < (tmp_body?.state || []).length; i++) {
                tmp_body.state[i]['value'] = null;
            }
            new_body = JSON.stringify(tmp_body);
        }

        if (moreArgs) {
            moreArgs.forEach(([key, value]) => addArg(key, value));
            moreArgs = moreArgs.filter(([_, __, single]) => !single);
        }

        return fetch(
            url,
            mergeDeepRight(config.fetch, {
                method: 'POST',
                headers,
                body: new_body
            })
        );
    };

    return new Promise((resolve, reject) => {

Review comment (performance):
nitpick: I think it would be more efficient to keep body as is and instead call the stringify only in the merge on line 476.

Code after:
    let runningOff: any;
    let progressDefault: any;
    let moreArgs = additionalArgs;

    if (running) {
        dispatch(sideUpdate(running.running, payload));
        runningOff = running.runningOff;
    }

    const fetchCallback = () => {
        const headers = getCSRFHeader() as any;
        let url = `${urlBase(config)}_dash-update-component`;
        let newBody = body;

        const addArg = (name: string, value: string) => {
            let delim = '?';
            if (url.includes('?')) {
                delim = '&';
            }
            url = `${url}${delim}${name}=${value}`;
        };
        if (cacheKey || job) {
            if (cacheKey) addArg('cacheKey', cacheKey);
            if (job) addArg('job', job);

            // clear inputs as background callback doesnt need inputs, just verify for context
            const tmpBody = JSON.parse(newBody);
            for (let i = 0; i < tmpBody.inputs.length; i++) {
                tmpBody.inputs[i]['value'] = null;
            }
            for (let i = 0; i < (tmpBody?.state || []).length; i++) {
                tmpBody.state[i]['value'] = null;
            }
            newBody = JSON.stringify(tmpBody);
        }

        if (moreArgs) {
            moreArgs.forEach(([key, value]) => addArg(key, value));
            moreArgs = moreArgs.filter(([_, __, single]) => !single);
        }

        return fetch(
            url,
            mergeDeepRight(config.fetch, {
                method: 'POST',
                headers,
                body: newBody
            })
        );
    };