참고링크 :
https://ko.reactjs.org/docs/context.html#when-to-use-context
https://www.youtube.com/watch?v=5LrDIWkK_Bc
<ThemeContext.Consumer>
식으로 감싸야 하지만, functional type 컴포넌트는 useContext Hooks를 활용함실제 적용 예시 (Functional Component 기준)
실습내용
:themecolor와 colorupdate 함수를 전역 state로 공유할 수 있도록 상태관리 구현
1. 버튼 클릭 시 themeColor를 boolean 변화값에 의해 변경되도록 구현 예정 (실제 dart <-> light mode 변경 시 활용)**
2. React.CreateContext() 함수를 활용하여 context 객체 생성const ThemeContext = React.createContext(); const ThemeUpdateContext = React.createContext();
3. ThemeProvider라는 글로벌 변수를 정하고 하위로 전파시키는 컴포넌트를 정의
- 예제에서는 themeColor라는 boolean 변수와, 이를 바꾸는 toggle 함수 변수를 정의하고 value로 할당
export const ThemeProvider = ({ children }) => { const [themeColor, setThemeColor] = useState(true); const themeToggle = () => { setThemeColor((prevThemeColor) => !prevThemeColor); }; return ( <ThemeContext.Provider value={themeColor}> <ThemeUpdateContext.Provider value={themeToggle}> {children} </ThemeUpdateContext.Provider> </ThemeContext.Provider> ); };
4. 사용하고자 하는 하위 컴포넌트에서 간단하게 쓸 수 있도록 custom hooks를 정의
export function useTheme() { return useContext(ThemeContext); } export function useThemeUpdate() { return useContext(ThemeUpdateContext); }
5. 적용하고자 하는 범위에 해당하는 최상위 컴포넌트로 wrap (in App.js)
6. 사용하고자 하는 하위 컴포넌트에서 custom hooks를 import하고, 변수로 할당하여, 사용원하는 곳에 삽입하면 끝!import { useTheme, useThemeUpdate } from '../hooks/ThemeContext';
const themeColor = useTheme(); const colorUpdate = useThemeUpdate();
<Text style={[styles.title, { color: themeColor ? '#EF904F' : '#9e50ed' }]}> 당근마켓 </Text>
<TouchableOpacity style={[ styles.button, { backgroundColor: themeColor ? '#EF904F' : '#9e50ed' }, ]} onPress={() => colorUpdate()} > <Text style={styles.buttonText}>내동네 설정하고 시작하기</Text> </TouchableOpacity>
참고사이트: https://velopert.com/3528
Redux
는 자바스크립트 앱을 위한 예측가능한 컨테이너React-Redux
는 리액트를 위한 공식 Redux UI binding Library. (React와 Redux를 함께 사용하는 경우, 두 라이브러리를 결합하기 위해 React Redux를 사용해야 함1. 전체 상태 값이 하나의 자바스크립트 객체로 표현됨
2. 상태 값은 읽기 전용의 불변객체로 관리
dispatch
를 호출하는 것 (마치 setState
)3. 오직 순수함수에 의해서만 상태값을 변경
실제 적용 연습
실습내용
: 기존 React Native 앱에서 i) 유저의 로그인 여부와 ii) 유저가 선택한 카테고리 리스트(필터링 키워드)에 대한 state를 redux 적용하여 변환해보기
1. 액션 생성함수 정의(액션 객체를 생성)// src > store > actions.js export const loginUser = (isLoggedIn) => { return { type: 'VERIFY_LOGIN', payload: isLoggedIn, }; }; export const addCategory = (selectedItem) => { return { type: 'ADD_CATEGORY', payload: selectedItem, }; }; export const deleteCategory = (selectedItems) => { return { type: 'DELETE_CATEGORY', payload: selectedItems, }; };
스토어에 액션 객체를 전달하기 위하여, 스토어의 내장함수인 dispatch hooks 정의
- 인자로 위의 액션객체를 전달해야 함
- dispatch가 실행되면 액션 객체는 리듀서로 전달 되고, 리듀서 내에 미리 정의해둔 조건문과 action.type에 따라 따라 스토어가 업데이트 됨
const dispatch = useDispatch()
2. dispatch를 통해 전달된 액션객체에 따라 새로운 상태값을 만드는 ruducer 함수 정의// store > reducers > index.js import { combineReducers } from 'redux'; import loginReducer from './loginReducer'; import categoryReducer from './categoryReducer'; export default combineReducers({ loginReducer, categoryReducer }); // loginReducer.js export const loginReducer = (state = false, action) => { switch (action.type) { case 'VERIFY_LOGIN': return (state = !state); default: return state; } }; // categoryReducer.js const categoryReducer = (state = INITIAL_STATE, action) => { switch (action.type) { case 'ADD_CATEGORY': return [...state, action.payload]; case 'DELETE_CATEGORY': return [...action.payload]; default: return state; } }; const INITIAL_STATE = []; export default categoryReducer;
3.스토어(store)의 값에 영향범위에 있는 컴포넌트를 감싸주기 (App.js)
- 스토어는 리덕스의 상탯값을 가지는 단일 객체이며, 프로젝트 어디서든 접근할 수 있다 (Provider)
- 액션 ⇒ 미들웨어 ⇒ 리듀서 ⇒ 스토어 업데이트 ⇒ 컴포넌트 업데이트
//App.js .. import { createStore } from 'redux'; import { Provider } from 'react-redux'; import rootReducer from './src/store/reducers'; .. const store = createStore(rootReducer); .. <Provider store={store}> .. </Provider>
4. 상태 값을 사용하고자 하는 컴포넌트에서 useSlector과 useDispatch를 활용하여 사용 (styled Components의 themeProvider와 같은 원리)
- useSelector 는 엄격한 비교 ( === )를 하여, 참조가 달라지면 무조건 업데이트 해준다.
- useSelector에는 두 번째 인자로 동일성을 검사하는 함수를 넣어줄 수 있다. react-redux가 제공하는 shallowEqual을 사용할 수 있으나, 일반적으로 불필요.
//categorySearch.js .. import { useSelector, useDispatch } from 'react-redux'; import { addCategory, deleteCategory } from '../store/actions'; .. export default function CategorySearch() { const checkedItems = useSelector((store) => store.categoryReducer); const dispatch = useDispatch(); .. const listRenderUnit = ({ item, index }) => ( <View style={{ width: 170 }}> <CheckBox id={index} title={item.name} checkedColor="#EF904F" uncheckedIcon="check-circle" checkedIcon="check-circle" onPress={() => { if (!checkedItems.includes(item)) { return dispatch(addCategory(item)); } else { const filteredItems = checkedItems.filter( (each) => each.id !== item.id ); dispatch(deleteCategory(filteredItems)); } }} checked={checkedItems.includes(item) ? true : false} /> </View> ); .. }
=> 아래와 같이, 너무 잘 작동한다. 신세계다! 원하는 카테고리명을 한번 클릭하면, store의 state 값인 리스트에 추가되고, 두번 클릭하면 제거된다.
(기타- middleware)
const middleWare = store => next => action => next(action);
참고링크
https://mobx.js.org/getting-started
https://www.youtube.com/watch?v=tjHljJRooHU
https://wix.github.io/react-native-navigation/docs/third-party-mobx/
주요개념
1. (Observable) State
: Graphs of objects, arrays, primitives, references that forms the model of your application.
: These values are the “data cells” of your application.
2. Derivation
: Basically, any value that can be computed automatically from the state of your application.
: These derivations, or computed values, can range from simple values, like the number of unfinished todos, to complex stuff like a visual HTML representation of your todos.
(In spreadsheet terms: these are the formulas and charts of your application.)
3. Reactions
:Reactions
are very similar to derivations.
: The main difference is these functions don't produce a value. Instead, they run automatically to perform some task.
: Usually this is I/O related. They make sure that the DOM is updated or that network requests are made automatically at the right time.
4. actions
: Actions are all the things that alter the state.
: MobX will make sure that all changes to the application state caused by your actions are automatically processed by all derivations and reactions. Synchronously and glitch-free.
실제 적용 연습
(내용) 당근마켓 클로닝 프로젝트에서, 위에서 Redux 적용 대상이었던, category list state를 전역으로 관리하도록 구현
import React from 'react';
import { makeObservable, observable, action } from 'mobx';
class CategoryStore {
categories = [];
constructor() {
makeObservable(this, {
categories: observable,
addCategory: action,
removeCategory: action,
});
}
addCategory = (item) => {
this.categories = [...this.categories, item];
};
removeCategory = (item) => {
this.categories = this.categories.filter((each) => {
each.id !== item.id;
});
};
}
const categoryStore = new CategoryStore();
export const CategoryStoreContext = React.createContext(categoryStore);
export const useCategoryStore = () => React.useContext(CategoryStoreContext);
categories
)의 변화를 감지하기 위한 observer와 custom hook을 importimport { observer } from 'mobx-react';
import { useCategoryStore } from '../store/CategoryStore';
그리고, 전체 컴포넌트를 observer로 감싸주기
export default observer(CategorySearch);
const { categories, addCategory, removeCategory } = useCategoryStore();
<CheckBox
id={index}
title={item.name}
checkedColor="#EF904F"
uncheckedIcon="check-circle"
checkedIcon="check-circle"
onPress={() => {
!categories.includes() ? addCategory(item) : removeCategory(item);
console.log(categories);
}}
checked={categories.some((each) => each.id === item.id) ? true : false}
/>