You are conflating tooling and platform.
Truffle is tooling. You don't deploy to truffle, but it can be handy to use truffle to deploy to dev/test and production platforms.
Ganache is platform. Regardless of tooling (in your case, a React app), Ganache is a valid platform for dev/test both in terms of cost and in terms of developer productivity. Consider using that as you iterate over your React app.
You should probably consider platform dependencies for your React app. Will you proceed on the assumption that users have a full node nicely synced up, do you want to minimize dependencies or do you want to offer a choice? You'll need a Web3 "provider". If you so choose, you can have multiple providers conditionally chosen at runtime, i.e. Look for full node or fall back to Infura if there is no full node.
Deploying a contract involves a specially crafted transaction, signed by the deployer and sent to address
Web3 itself has gone through significant changes, so many of the examples found online are outdated. I did some searching for a recent example with reasonably concise code. This
node example seems appropriate and hopefully, you can extrapolate from that for your React implementation. I realize it's an issue report.
Hope it helps.