UNET Can't set up nicknames above players properly

Hello guys!
I’m new to UNET system and i’m trying to understand how this whole system works. After i have watched unity tutorial for networking i started adding my features and my first feature was nicknames. I have two scenes in a project (offline - where i can create game or join AND type my nickname, and online for gameplay) During the gameplay i want the nicknames to appear above player prefabs.

I have 2 problems:
First one is when a player joins the server. I don’t know where exactly put the method to refresh all texts above and what kind of method should it be. When i want to refresh names in “OnStartLocalPlayer” function it doesn’t work, but when i press the button which refreshes those names - it works.(code below)
From my observations it looks like refresh in the funtion “OnStartLocalPlayer” could work, but the name is not yet synchronized along players.

Second one - How can i pass data between the scenes - a nickname in this situation. I’ve found a temporary solution for this by using PlayerPrefs, but maybe there is some better way.

I would appreciate your help

The code:

[SerializeField]public UnityEngine.UI.Text nickname;

[SyncVar]
public string playerName;

void Update()
{
    if (Input.GetKeyDown(KeyCode.F1))
    {
        GameObject[] players = GameObject.FindGameObjectsWithTag("Player");

        foreach (GameObject p in players)
        {
            Debug.Log(p.GetComponent<newStats>().playerName);
            p.GetComponent<newStats>().nickname.text = p.GetComponent<newStats>().playerName;
        }
    }
}

public override void OnStartLocalPlayer()
{
    CmdSetName();
    nickname.text = playerName;
}

void OnPlayerConnected(NetworkPlayer player)
{
    GameObject[] players = GameObject.FindGameObjectsWithTag("Player");

    foreach (GameObject p in players)
    {
        Debug.Log(p.GetComponent<newStats>().playerName);
        p.GetComponent<newStats>().nickname.text = p.GetComponent<newStats>().playerName;
    }
}

[ClientRpc]
void RpcRefreshNames()
{
    GameObject[] players = GameObject.FindGameObjectsWithTag("Player");

    foreach (GameObject p in players)
    {
        Debug.Log(p.GetComponent<newStats>().playerName);
        p.GetComponent<newStats>().nickname.text = p.GetComponent<newStats>().playerName;
    }
}

[Command]
void CmdSetName()
{
    playerName = PlayerPrefs.GetString("name");
}

Okey i’ve found the answer on my own. I’ve added new variable for players amount, which is updated after name assigning. I hooked the variable and in the hook i update names.

[SerializeField]public UnityEngine.UI.Text nickname;

[SyncVar]
public string playerName;

[SyncVar(hook = "OnPlayersAmountChange" )]
public int playersAmount;

public override void OnStartLocalPlayer()
{
    CmdSetName();
    nickname.text = playerName;
    CmdUpdatePlayersAmount(playersAmount+1);
}
    
public void OnPlayersAmountChange(int amount)
{
    //Debug.Log(amount);
    playersAmount = amount;

    GameObject[] players = GameObject.FindGameObjectsWithTag("Player");

    foreach (GameObject p in players)
    {
        //Debug.Log(p.GetComponent<newStats>().playerName);
        p.GetComponent<newStats>().nickname.text = p.GetComponent<newStats>().playerName;
    }

    RpcSetPlayersAmount(players.Length);
}

[ClientRpc]
void RpcSetPlayersAmount(int amount)
{
    playersAmount = amount;
}

[Command]
void CmdSetName()
{
    playerName = PlayerPrefs.GetString("name");
}

[Command]
void CmdUpdatePlayersAmount(int newValue)
{
    playersAmount = newValue;
}