Рубрики
Без рубрики

Объедините объектив и контекст и крючки для управления глобальным государством в React

Полный код: выпуск5 Недавно я работал над личными проектами с React. Поскольку это не большой … Tagged with React, JavaScript.

Полный код: Выпуск5

Недавно я работал над личными проектами с React. Поскольку это не крупные проекты, я решаю избавиться от любой библиотеки управления государством.

Для уровня компонентов это просто, мы можем просто использовать крючки, чтобы решить это, например, usestate, пользователь. Но как управлять глобальным государством в приложении React? К счастью, у нас есть контекст. Таким образом, мы можем просто управлять состоянием в компоненте верхнего уровня с пользовательским средством и использовать контекст для передачи этих данных в детские компоненты.

export interface IProfile {
  name: string;
  age: number;
  country: string;
}

export interface IUser {
  id: number;
  profile: IProfile
}

export interface IStore {
  user: IUser;
}

export const initialStore: IStore = {
  user: {
    id: 0,
    profile: {
      name: 'initial user name',
      age: 0,
      country: 'anywhere'
    }
  },
}

export type Action = (store: IStore) => IStore; // explain later

export interface IStoreContext {
  store: IStore,
  dispatch: (action: Action) => void;
}

export const initialContext: IStoreContext = {
  store: initialStore,
  dispatch: () => {
    throw new Error('this initial function should never be called')
  }
}

export const StoreContext = React.createContext(initialContext);

// explain later
export function reducer(store: IStore, setter: Action) {
  return setter(store);
}

import React from 'React';

import { reducer, initialStore, StoreContext } from './Context/StoreContext';

export function App() {
    
      
{({ store, dispatch }) => { return (

{JSON.stringify(store)}

) }}
}

Пока выглядит хорошо, мы решаем глобальное управление государством с контекстом и крючками. Но есть несколько проблем, меня очень беспокоит. Обычно, когда мы используем Reducer, мы намерены определить много действий и обновление Store, используя большой оператор Switch.

export interface IUpdateUserName {
  kind: 'updateUserName'
  payload: {
    username: string
  }
}

type Action = UpdateUserName

export function reducer(store: IStore, action: Action) {
  switch(action.kind) {
    case 'updateUserName':
        return {
            ...store,
            user: {
                ...store.user,
               profile: {
                   ...store.user.profile,
                   username: action.payload.username
               }
            }
        };
    break;
  }
}


// Then we can dispatch action in component like this
dispatch({
  action: 'updateUserName',
  payload: {
    username: 'new user name'
  }
})

Рассмотрим приведенный выше код, на самом деле не очень приятно обновлять вложенную собственность в штате, хотя оператор спреда спас нас много работы, и проверка типов может убедиться, что мы не обновляем неправильное поле, но можем ли мы сделать его лучше?

Тогда я действительно почему бы не использовать объектив и просто отправить сеттер? Вот почему сначала тип действия определяется как

export type Action = (store: IStore) => IStore

Если вы не знакомы с объективом, вы можете считать его комбинацией функции Getter и Setter. Getter используется для чтения значения, а Setter используется для обновления значения. Вот простая версия объектива

export interface ILens {
    get: (a: A) => B;
    set: (b: B) => (a: A) => A;
}

// construct a Lens from property name
// get will be a function to read property object object
// set will be a function to set value of object
export function lens(prop: P): ILens {
    return {
        get: (a: A) => {
            return a[prop];
        },
        set: (propValue: A[P]) => {
            return (a: A) => {
                return {
                    ...a,
                    [prop]: propValue,
                }
            }
        }
    }
}

// compose can combine a fuction to form another Lens
//  it's useful when we want to read/write nested value
export const compose = (lensAB: ILens) => {
    return (lensBC: ILens): ILens => {
        return {
            get: (a: A) => {
                return lensBC.get(lensAB.get(a))
            },
            set: (c: C) => {
                return (a: A) => {
                    const b = lensAB.get(a);
                    const updatedB = lensBC.set(c)(b)
                    return lensAB.set(updatedB)(a)
                }
            }
        }
    }
}

Далее мы можем определить несколько объектива для собственности ISTORE и посмотреть, как отправить объектив, чтобы обновить имя пользователя

export const storeUserLens = lens('user');
export const userProfileLens = lens('profile')
export const profileNameLens = lens('name');

export const storeUserProfileLens =
  compose(storeUserLens)(userProfileLens)

export const storeUserProfileNameLens =
  compose(storeUserProfileLens)(profileNameLens)



// In component, we can use getter to retrive nested value and dispatch a setter to update user name
          
            {({ store, dispatch }) => {
              return (
                

{storeUserProfileNameLens.get(store)}

) }}

Обратите внимание, что это определение объектива не очень хорошо сформировано, вы хотите использовать объектив в своем проекте, вы можете попробовать монокл-т

Оригинал: “https://dev.to/jacobchang/combine-lens-context-hooks-to-manage-global-state-in-react-1eg3”