Redux

hyena_lee·2023년 2월 24일
0

TIL

목록 보기
30/42
post-thumbnail

리덕스란 ?

Redux is a predictable state container for JavaScript apps.
자바스크립트 애플리케이션을 위한 상태 관리 라이브러리 입니다.

그래서 Redux는 State을 관리하는 것

import { createStore } from 'redux'

/**
(state, action) => state 형태의 순순 함수의 리듀서입니다.
리듀선느 액션이 어떻게 상태를 다음 상태로 변경하는지 서술.
기본형(primitive)일수도, 배열일수도, 객체일수도
심지어 immutable.js 자료구조임.
중요한 점은 상태 객체를 변경해서는 안된다. 
상태가 바뀐다면 새로운 객체를 반환해야 한다는 것.
'Switch' 구문과 문자열로 써서 예제를 설명.
*/

function counter(state = 0, action) {
	switch (action.type) {
    	case 'INCREMENT':
        	return state + 1
        case 'DECREMEENT':
        	return state -1
        default:
        	return state
    }
 }
 
/** 
앱의 상태를 보관하는 Redux 저장솔르 만든다.
API로는 = { subscribe, dispatch, getState }가 있습니다.
*/

let store = createStore(counter)

/**
subscribe()를 이용해 상태변화에 따라 UI 가 변경되게 할 수 있다. 
보통은 subscribe() 를 직접 사용하기보다는 뷰 바인딩 라이브러리(예를 들어 React Redux)를 사용한ㄷ.
하지만 현재 상태를 localStorage애 영속적을 저장할 때도 편리
*/
store.subscribe(()= > console.log(store.getState())) 

/** 
내부 상태를 변경하는 유일한 방법을 액셕을 보낸다.
액션은 직렬화 할 수도, 로깅할수도, 저장할수도 있으며 나중에 재실행할 수 도 있다.
*/

store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })

상태를 바로 변경하는 대신, 액션이라는 불리는 평범한 객체를 통해 일어날 변경을 명시.
그리고 각각의 액션이 전체 애플리케이션의 상태를 어떻게 변경할지 결정하는 특별한 함수의 리듀서이다.

보통의 Redux 앱에는 하나의 리듀서 함수를 가진 단 하나의 저장소가 있다. 앱이 커짐에 따라 루트 리듀서를 상태 트리의 서로 다른 부분에서 개별적으로 동작하는 작은 리듀서들로 나눌 수 있다. React앱을 하나의 루트 컴포넌트에서 시작해서 작은 컴포넌트의 조합으로 바꾸는 것과 동일하다.

Redux를 사용해야 할까요?

Redux는 상태를 관리하기에 좋은 도구이지만 여러분의 상황에 적당한지는 따져 보아야 합니다. 단지 누군가가 사용하라고 했다는 이유만으로 Redux를 사용하지는 마세요 - 시간을 들여서 잠재적인 이점과 그에 따르는 단점을 이해하는게 중요하다

Redux를 사용하기 적절한 때를 알기 위한 몇 가지 제안이 있습니다:

  • 계속해서 바뀌는 상당한 양의 데이터가 있다
  • 상태를 위한 단 하나의 근원이 필요하다
  • 최상위 컴포넌트가 모든 상태를 가지고 있는 것은 더 이상 적절하지 않다

getState() : 애플리케이션의 현재 상태 트리를 반환한다. 스토어의 리듀서가 반환한 마지막 값과 같습니다.

const render = (0 => root.rnder (
  <React.StricMode>
  	<App
  		value={store.getState()}
		onIncrement={() => store.dispatch({ type: "INCREMENT })}
		onDecrement={() => store.dispatch({ type: "DECREMENT })}
	/>
  </React.StrictMode>
);
render();

store.subscribe(render);

Subscibe()

change listener를 추가합니다. 작업이 전달될 때마다 호출되며 상태 트리의 일부가 잠재적으로 변경되었을 수 있다. 그런 다음 getState() 를 호출하여 콜백 내부의 현재 상태 트리를 읽을 수 있다.

root reducer와 sub reducer

counter 리듀서만 있는데 하나를 더 추가해주려면
Root 리듀서를 만들어서 그 아래 counter 와 todo라는 서버(sub)리듀서를 넣어주면 된다. Root 리듀서를 만들 때 사용하는 것이 combineReducers 이다.

index.tsx

import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'

const rootReducer = combineReducers({
	todos,
  	counter
})

export default. rootReducer;

todos.tsx

enum ActionType {
  ADD_TOD = "ADD_TODO",
  DELETE_TODO = "DELETE_TODO"
}

interface Action {
	type: ActionType;
  	text: string;
}

const todos = (state = [], action: Action) => {
	switch (action, type) {
      case 'ADD_TODO':
        	return [...state, actoion.text]
      default:
        	return state
    }
}

export default todos;

counter.tsx

interface Action {
	type: string
}

const counter = (state = 0, action: Action) => {
	switch (action.type) {
      case 'INCREMENT':
        	return state +1
      case 'DECREMENR':
        	return state -1
      default: 
        	return state
    }
}

export default counter;

createStore에 루트 리듀서로 대체

import counter from './reducers;
import { createStore } from 'redux'

const store = createStore(counter)
import rootReducer from './reducers';
import { createStore} from 'redux'

const store = createStore(rootReducer)

store.getState()

const store = createStore(rootReducer)

store.dispatch({
	type: 'ADD_TODO',
  	text: 'Use Redux'
})
console.log('store.getState()', store.getState());

Provider란?

구성 요소는 Redux Store 저장소에 액세스해야 하는 모든 중첩 구성 요소에서 Redux Store 저장소를 사용할 수 있도록 합니다.
React Redux 앱의 모든 React 구성 요소는 저장소에 연결할 수 있으므로 대부분의 응용 프로그램은 전체 앱의 구성 요소 트리가 내부에 있는 최상위 수준에서 를 렌더링합니다.
그런 다음 Hooks 및 연결 API는 React의 컨텍스트 메커니즘을 통해 제공된 저장소 인스턴스에 액세스할 수 있습니다.

Provider 컴포넌트 이용하기

React Redux 앱의 모든 React 컴포넌트는 리덕스 Store에 연결할수 있으므로 대부분의 프로젝트에서는 최상위 컴포넌트에서 를 렌터디링 한다. => Index.js에서 Privider 이용

const store = createStore(rootReducer)
  
store.duspatch({
	type: 'ADD_TODO',
  	text: 'Use Redux'
})
  
ReactDOM.render(
	<React.StricMode>
      <Provider store={store}>
        <App
          onIncrement={() => store.dispatch({ type: "INCREMENT'})}
          onDecrement={() => store.dispatch({ type: "DECREMENT })}
         />
       </Provider>
      </React.StrictMode>,
      document.getElementById('root')
);

Todo UI 생성

<ul>
</ul>
      
<form onSubmit={addTodo}>
	<input ty[e="text" value={todoValue} onChange={handleChange} />
  	<input type="submit" />
</form>
      

const [todoValue, setTodoValue] = useState("");
      
      
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      setTodoValue(e.target.value);
}
      
 const addTodo = (e: React.FormEvent<HTMLFormElement>): void => {
 	e.preventDefault();
    setTodoValue("");
 }
      

provider로 둘러 쌓인 컴포넌트에서 store접근

리액트에 Hooks가 있듯이 리덕스에도 Hooks가 있는데 그게 바로 useSelector와 useDispatch입니다. 이 두 개를 이용해서 provider로 둘러싸인 컴포넌트에서 store에 접근 가능합니다.

useSelector

useSelector Hooks를 이용해서 스토어의 값을 가져올 수 있습니다.
const result: any = useSelector(selector: Function, equalityFn?: Function)

const counter = useSelector((state) => state.counter)      
      
  1. Root Reducer에 RootState 타입을 생성하기

    const rootReducer = combineReducers({
    	todos,
       counter
    })  
    
    export default rootReducer;
         
    export type RootState = ReturnType<typof rootReducer>;
        

2. 생성한 RootState을 State 객체에 제공하기

const todos: string[] = useSelector((state: RootState) => state.todos)
const counter = useSelector ((state: RootState) => state.counter)
      
      
<ul>
  {todos.map((todo, index) => <li key={index}>{todo}</li>)}
</ul>
      
 <form onSubmit={addTodo}>
   <input type="text" value={todoValue} onChange={handleChange} />
   <input type ="submit" />
 </form>
      
      
profile
실수를 두려워 말고 계속 도전 하는 개발자의 여정!

0개의 댓글