Why is row-level access needed when views can limit a person's access to rows and/or columns?
I'm assuming you're asking this question in the context of Microsoft SQL Server since Row-Level Security is a feature they offer. While there are similarities between using a View to implement a mock row-level security and using the Row-Level Security feature of SQL Server, there are a few differences as well:

Separation of Concerns - Row-Level Security abstracts out the security portion from your entities to allow for cleaner and simpler code.

Manageability - With Row-Level Security, you create a Policy entity that Users can be added to. That Policy leverages a Function where you define your logic for the security Policy. This eliminates the need for custom Table(s) to store your users and their access roles.

Reusability - You can use the same Policy for multiple Tables without the need of coding repeated logic.

Flexibility - You can easily turn the Policy ON and OFF for any Table by setting the STATE of that Policy.

Performance - Generally the custom logic used to emulate security at the Row-Level in Views can negatively affect performance if the predicates are too complicated. I've seen great performance improvements by removing this logic from your View's predicates and creating an Inline Table Valued Function with the same exact logic used in a Policy for Row-Level Security. (I don't fully know why but by looking at the Execution Plan in both scenarios, there is definitely a difference which I think is related to the security logic being abstracted out and applied separately from the predicates in the View.)


For more information you can read on Microsoft's Row-Level Security docs.