React 컴포넌트 밖에서 State 업데이트 하기

곰튀김·2024년 2월 21일
0
post-thumbnail

Component 밖에서 State를 업데이트 하자

  • 관심사 분리
  • testability 확보
  • 재사용성 증대
  • 가벼운 컴포넌트

고려사항

  • 최대한 사용하기 편하게
  • 기존 React 사용성에서 벗어나지 않게
  • 디버깅 용이하도록
  • async 작업을 쉽게

테크스택

  • redux-toolkit
  • react-redux

Store.ts

const store = configureStore({
  reducer: {
    app: appSlice.reducer,
  }
});

export type RootStoreType = ReturnType<typeof store.getState>;

AppSlice.ts

const name = "appSlice";
const initialState = {
  message: "",
  count: 0,
}

const appSlice = createSlice({
  name,
  initialState,
  reducers: {
    setMessage: (state, action) => {
      state.message = action.payload;
    },
    clearMessage: (state) => {
      state.message = "";
    },
    setCount: (state, action) => {
      state.count += action.payload;
    },
  }
});

App.tsx

function App() {
  const appState = useSelector((state: RootStoreType) => state.app);
  const controller = useController(() => new AppController());

  return (
    <>
      <div>
        <p>{appState.count}</p>
        <button className={'border p-1 m-1'}
                onClick={() => controller.increase()}
		>
        	Increase
		</button>
		<p className={'text-xs text-gray-300'}>{appState.message}</p>
      </div>
    </>
  )
}

useController.tsx

export const useController = <T, >(builder: () => T) => {
  const [controller] = useState(builder);
  return controller;
}

AppController.tsx

export class AppController {

  private readonly appAction;

  constructor() {
    this.appAction = bindActionCreators(appSlice.actions, store.dispatch);
  }

  async increase() {
    this.appAction.setMessage("pending..");
    await new Promise(resolve => setTimeout(resolve, 1000));
    this.appAction.setCount(1);
    this.appAction.clearMessage();
  }
}
  • AppContoller 에서 async 작업 수행
  • 이 코드는 testibility 가 고려되어 있지 않음 (구현하기 나름)
profile
사실주의 프로그래머

1개의 댓글

comment-user-thumbnail
2024년 6월 25일

이제와서 생각해 보니. 이 방법은 react 의 매커니즘을 잘 이해하지 못한 상태에서 어떻게든 꾸역꾸역 한 티가 팍팍 난다. 이제 이 글은 Deprecated 됩니다.

답글 달기