Generally speaking salts and hashes are done server-side, not client side. The communication between server and client should be protected with encryption (TLS). As Anders mentions in a comment this may answer a lot of your questions: For an HTTPS web application, is it worthwhile to encrypt the password before POSTing it, to keep a MITM attacker from harversting it?
About salts and hashing in general: the idea behind salts and hashes often boils down to forcing the attacker to perform a brute-force algorithm. This both (a) buys the service time to secure the network and change user passwords, and (b) prevents bad actors inside the company/website from acquiring the user's password (for naughty things like trying that password on other sites).
Salts do many things. (1) protects against rainbow table attacks like you said, (2) in the case of data breach, it makes password-cracking more difficult than vanilla hash (that is, there's no way an attacker can build a database of all hashes for an algorithm; they'd have to have that database for every hash, which is not feasible); this buys the site/users time to change the algorithm and passwords, (3) prevents people working for the site to be able to easily steal a user's password, and (4) grants more architectural options for securing the authentication process.
To talk about (4) for a minute, a (very large international) client of mine had a microservice architecture, and their authentication processes worked by hashing the password with one of many salts (based on username) before sending it to the microservice which checked the actual database. This type of separation prevented the code handling the database to know both salt and password, and the microservice which knew the salt would not keep hashes (neither in-memory nor on-disk). An attacker could not use a database dump; they'd need database and software from more than one server. This increases complexity, as a stolen database gets them no closer to hashing the database; they'd also need the list of salts (from another server). No employee had access to both servers, which helped with (3).
Why hashing client-side isn't super useful:
A man in the middle attack can capture whatever is transmitted between the client and the server. Hashing the password before sending does very little; the attacker doesn't have to be able to generate the hash, they'd just have to send the exact same request again to get access.
For example, let's look the following requests and parameters (I'm not using real HTTP headers for readability):
POST /auth/login
user=me@example.com
pass=mypassword
versus:
POST /auth/login
user=me@example.com
pass=89e01536ac207279409d4de1e5253e01f4a1769e696db0d6062ca9b8f56767c8
The server can't know by the hash that the real password is "mypassword", so it'll just use the hash as-is to verify the user's account. An attacker who can read that request doesn't need to know that your password is "mypassword", they just need to take the hash; that gives no protection for the account. The only thing this prevents is the attacker being able to test the password on other sites (eg, many people foolishly use the same email and password for google and their bank).