Handling initialisation and avoiding races during prefab instantiation

How would experienced Unity developers recommend doing the determination of the damageText’s Text component programmatically, instead of using a SerializedField as per the video?

For example, I can recursively find a Text component with GameObject.GetComponentsInChildren().

However I’ve run into a problem with instantiating prefabs that ties back to recent videos regarding Awake/Start and avoiding race conditions - let’s say I want to cache the reference I find to the Text component in DamageText.Start(). It turns out that Start for the new component instance doesn’t run until the next frame, meaning that DamageTextSpawner.Spawn() cannot call DamageText.SetValue() in the same frame it instantiated it in. It would have to wait at least one frame to avoid a data hazard.

Awake() on the component instance runs immediately, but I can’t cache the reference to Text there because there’s no guarantee that the child objects have actually been initialised yet (Is that true? Or can I rely on this?).

Just wondering what experienced Unity developers like @sampattuzzi would do in this situation? Defer to a CoRoutine to give Start() a chance to run first? Use Awake() with some knowledge that it’s safe to do so? Initialise the reference cache in SetValue itself?

I’d like to understand a best-practice that works correctly even if the prefab is included as a scene asset.

Note: oddly, according to official docs, GameObject.GetComponentsInChildren() is recursive through the entire hierarchy of the object, but component.GetComponentsInChildren() and GameObject.GetComponentInChildren() are not!