Properly represent/update state and separate processor & editor thread?

Novice question incoming:

When I first mocked up my plugin I started by writing part of the UI, and storing all the parameter state in my various UI components. I’ve since learned that the correct pattern is to store all state required by the audio processor in the audio processor itself, because the audio processor cannot call UI components for performance reasons. I’m currently working on a refactor where I move the state variables to the processor thread and update them via getters/setters when my UI components are updated.
This feels awkward, however, because it has meant that I have had to pass my instance of the audio processor to the constructors of all my UI components, so that they can access those getters and setters when a slider updates, or what have you. And to briefly address the thread safety here - I know that just naively getting/setting is not a thread safe action, but I have been avoiding locking/critical section style thread safety (what I am most familiar with from school) because I understand this to be bad practice for audio development that relies on the callback loop. Should I be implementing some kind of lock-free data structure to send state back/forth, should I not attempt to access state at all from the UI thread and instead keep a separate copy of said state within the component, are my assumptions about audio development even correct? State manipulation is like, basic programming literacy, so how do people manipulate the variables your UI controls, such that the audio processor can access them, within the JUCE pattern, thread-safely?

Thanks!