You need to rebuild whole form, no way around it, but you can store expensive things in Drupal cache. I advise against storing parts of
$form array if it can be avoided, but using
cache_get() to keep things like options available for select B when there is X in select A, it should work like a charm. And it will work with APC and Memcache modules out of the box.
The key is, of course, careful selection of
$cid building algorithm.
$form_state as cache
$form_state is kept in form cache bin, but it is not a "real" cache. Let's look at the definition from Wikipedia:
In computer science, a cache (/ˈkæʃ/ KASH)1 is a component that transparently stores data so that future requests for that data can be served faster.
Now, that's pretty much what
$form_state is not - it is kept to save temporary data that needs to be consistent, and that are never stored anywhere else during form processing. It means that when someone is using APC or Memcache, he needs to take extra care to prevent their "it can be deleted without any reason, for performance purposes" approach from corrupting forms. Most Drupal admins I know simply exclude form cache bin from them. And that is not what you want for your pre-built form parts.
Your pre-built form parts are real cache. So you want to keep them in bins that will be treated accordingly, you want to have speed over stability - you can afford additional rebuild once and then more than you can afford slowing down each request by pulling this data from database - slowest cache possible for Drupal.
Second reason not to use it is scope.
$form_state exists only per one form session. So if user ends filling the form and access it again,
$form_state is build anew. If hundred of users access he same form at one time, you have a hundred instances of
$form_state. That's not what you want when your form elements does not depend on the user of your system. By keeping them in separate cache bin, keyed only by the things they depends on, you can have one copy, and use it for all hundred of users, every time they need it. It is impossible to loose anything, and you can decrease load (both CPU for generation and space for storage) to minuscule fraction of what it would be, if you would keep it in
Algorithm for using cache (if someone happens to forget, of for newbies reading in future):
- Check if data is in cache
- If not, build it and save to the cache
- Use either data obtained from cache in 1., or built in 2.