Linking two multiselect boxes with session_state keys and 'on_click' gives odd behavior

HI i’m trying to link two mulitselect boxes - so that once one option is picked from one box, it updates the list from another dynamically. So if I have a dataframe of ‘pets’, ‘farm animals’ & ‘wild animals’ , when I pick say ‘pets’ in one box , it will only give me examples of ‘pets’ (like a cat) in the other box. Here is my code. If you run it - it always seems to be one step behind the selection. is there an easy fix here ? thanks (P.S I tried submit form and it doesn’t help + i don’t want to use that anyway)

    "st.session_state object:", st.session_state

    df1 = pd.DataFrame(
        {'animals': ['cat', 'dog', 'cow', 'pig', 'tiger', 'wolf'],
         'type': ['pet', 'pet', 'farm', 'farm', 'wild', 'wild']

    if 'animal_selection' not in st.session_state:
        st.session_state.animal_selection = list(set(df1['animals'].to_list()))
    if 'type_selection' not in st.session_state:
        st.session_state.type_selection = list(set(df1['type'].to_list()))
    if not bool(st.session_state.type_selection):
        st.session_state.animal_selection = list(set(df1['animals'].to_list()))

    # animal = list(set(df1['animals'].to_list()))
    type = list(set(df1['type'].to_list()))

    ##### get list of columns for multiselect
    def types_to_animals():
        st.write('on change type_selction', st.session_state.type_selection)
        st.session_state.animal_selection = (set(df1[df1['type'].str.contains
        ('|'.join(st.session_state.type_selection), case=False)]['animals'].to_list()))
        st.write('on change animal_selction', st.session_state.animal_selection)

    ##### get sidebar boxes #####
    st.sidebar.title('Filter data')
    animal_search = st.sidebar.multiselect("start typing animal names", st.session_state.animal_selection,
                                           # key='animal_selection',
                                           ) #on_change=animals_to_types

    type_search = st.sidebar.multiselect("filter by type", type,
                                              on_change=types_to_animals) #

    if animal_search:
        df1 = df1[
            df1['animals'].str.contains('|'.join(st.session_state.animal_selection), case=False)]
    elif type_search:
        df1 = df1[
            df1['type'].str.contains('|'.join(type_search), case=False)]

in the image below you see I have selected ‘farm’ and ‘pet’ - but the st.session.state.animal_selection is only of farm animals - if you cycle through the type selection, the animal multiselect box alway seems to be one behind