Storing ajax callback variables in PrivateTempStore I have an issue with changing / obtaining variables in form element's ajax callback function. (Sorry for typos, I just placed a pieces of whole code).

I have form with input field, where user can select how many pieces of each product he want

$form['wrapper_amount']['value'] = [
        '#type' =&gt; 'number',
        '#prefix' =&gt; '&lt;div class="d-flex align-items-end form-element"&gt;',
        '#suffix' =&gt; '&lt;span class="form-element-unit"&gt;pcs&lt;/span&gt;&lt;/div&gt;',
        '#name' =&gt; "amount--product-1",
        '#ajax' =&gt; [
            'callback' =&gt; '::calculatePricePerUnit',
            'event' =&gt; 'change',
            'disable-refocus' =&gt; TRUE,
            'progress' =&gt; [
                'type' =&gt; 'fade',
                'message' =&gt; NULL,
            ],
        ],
    ];


after choosing a number I calculate price using AJAX callback function and using 

public function calculatePricePerUnit(array &amp;$form, FormStateInterface $form_state)
{
    // ... price calculation for specific product
    // $new_price = (amount * price_per_unit);

    $total_price = (float)$form_state-&gt;get('total_price_with_vat') + $new_price;
    $response = new AjaxResponse();
    $response-&gt;addCommand(
        new InvokeCommand(
            '#total-price',
            'html', [$form_state-&gt;get('total_price_with_vat') . ' €']
        )
    );
}


The problem is that when used add amount to second product the $form_state-&gt;get('total_price_with_vat') is 0 again. It means that I cant store $total_price variable in $form_state, because it's not persistent (I've already read this somewhere, that I can't store variables to $form_state in AJAX callback function). So I tried to store it to $form_state-&gt;setStorage($my_values) but it didn't work either.

Please note that all AjaxResponse commands are working and I only need to find best approach how to store data, not how to re-render form's elements.

My next step is to store data in PrivateTempStore, but question is, if it's good approach?
I don't need data on any other Wizard page, neither in Controller or any further step. I just need to calculate $total_price and some other data that I need to use multiple times in AJAX callback function, and at the end use webform API to send webform submission results via email.
PrivateTempStore is not the right fit for this. You want to store the value in the $form_state, but you do not store it in the AJAX callback, you store it in the submit handler, then set the form to rebuild (which will persist the values in the storage. You can set a custom #submit handler on your ajax submit button that is only called when that button is clicked:

$form['wrapper_amount']['value'] = [
  '#type' =&gt; 'number',
  '#prefix' =&gt; '&lt;div class="d-flex align-items-end form-element"&gt;',
  '#suffix' =&gt; '&lt;span class="form-element-unit"&gt;pcs&lt;/span&gt;&lt;/div&gt;',
  // note - #name is commented out, as you should never
  // need to change it in Drupal, and doing so will have
  // unexpected consequences. 
  // '#name' =&gt; "amount--product-1",
  '#ajax' =&gt; [
    'callback' =&gt; '::calculatePricePerUnit',
    'event' =&gt; 'change',
    'disable-refocus' =&gt; TRUE,
    'progress' =&gt; [
      'type' =&gt; 'fade',
      'message' =&gt; NULL,
    ],
  ],
  '#submit' =&gt; ['::customSubmit'],
];


Then your custom submit will look like this:

public function customSubmit(array &amp;$form, FormStateInterface $form_state) {
  $total_price = (float)$form_state-&gt;get('total_price_with_vat') + $new_price;
  $form_state-&gt;set('total_price', total_price);
  $form_state-&gt;setRebuild(TRUE);
}


After playing around with this a little, I can see that a submit button is required to be able to call a submit handler where rebuildForm() can be recalled. If you set the #ajax on a non-submit button, ajax is called, but rebuildForm() is not able to be called.

As such, I'd say the hack for this is to create an #ajax submit button as I've shown above, but hide it. Then add some custom JS on the number field, that on blur triggers a click of the hidden submit button.