There a few things worth noting here.
React Redux uses strict equality (reference equality) as the default method for comparisons. The immutable nature of Redux state means that any change to a deeply-nested property requires that all of its ancestor must be new object references.
If you update a.b.c then a and a.b must be new objects. Let's say that you have a sibling property tree like a.d.e. When you update a.b.c it causes a to be a new object reference, but a.d and a.d.e are the same. If you have a component that only needs to know about a.d then it should not need to re-render in response to your a.b.c change.
This is why it's important that each component should only select the minimal information that it needs from the state. You should connect more individual components rather than selecting a lot of information from state and passing it down through props. You can use multiple useSelector hooks in the same component to select small, granular pieces of state.
You do have the ability to customize the equality comparison by passing a comparison function as the second argument to the useSelector hook.
If you have a component that subscribes to the piece of state that's controlled by this reducer then you can use the shallowEqual function which is included in the react-redux package. I'm not sure if the reducer in your question is your root reducer or something that you are passing to combineReducers. I'm assuming it's just one piece.
Let's say it's for a property settings and you have some updateSettings action that merges the new settings with the existing ones. Then when you have a component that needs to access the settings, you would do this:
import { shallowEqual, useSelector } from 'react-redux'
const settings = useSelector(state => state.settings, shallowEqual);
This would mean that the component will only re-render if some of the settings have actually changed, even if state.settings is a new object. It is doing a shallow comparison between the current value of state.settings and the previous one.
It is possible to use a deep equals comparison like lodash's isEqual but I'm not seeing why you would need it as this reducer is making a shallow copy. If you need to do that expensive check anywhere then it seems more logical to do it before you dispatch the action in the component or before you return a new object from the reducer rather than on every call of the useSelector hook.
You asked about whether you should check for changes in the reducer before returning a new state object. That's a good idea and it's actually what a combined reducer created by combineReducers does, though it only checks for shallow equality. See lines 177-201 of the source code. If all of the individual property reducers returned the same object as before then it will return the previously combined state in order to maintain object references.