나는 국가를 위한 일반적인 환원기를 만들었고, 언제 사용해야 하는지, 언제 사용하지 말아야 하는지.
나는 환원점을 가지고 있다.저장소의 데이터를 변경하려면, 일반적인 방법은 조치, 조치크리에이터, 감속기를 만든 다음 조치를 발송하는 것이다.중소형 앱의 경우 이런 변화를 반영하기 위해 이렇게 많은 곳에서 바꾸는 것은 과잉 살상으로 보인다.그래서 이렇게 생긴 일반적인 환원기를 만들었다.
// here state is a copy of actual state, so I can mutate it directly
const reducer = ( state, action) => {
if(action.type == 'SETTER'){
try{
return assign(state, action.data.target, action.data.value )
}
catch(err){
console.log('WARNING: the key wasn\'t valid', err)
}
}
return state;
}
assign
방법은 다음과 같다.
const assign = (obj, prop, value) => {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e] , prop, value);
} else
obj[prop[0]] = value;
return obj
}
그리고 나는 일반적인 행동분석원과 컨테이너 구성요소를 가지고 있는데, 그것은 내가 이런 일을 할 수 있게 해준다.
containerComponent.set( 'user.name', 'Roy' )
containerComponent.set( 'order.receiver.address', 'N/A')
다음과 같은 경우에 발포되는 조치set
컨테이너에 가서 이렇게.
{
type : 'SETTER',
data : {
target : 'user.name',
value : 'Roy'
}
}
보시다시피 이 일반 환원기는 다시는 환원기를 쓸 수 없게 해주지만, 나는 여전히 상태가 변할 때마다 조치를 파견하고 있어 환원제의 핵심 원리를 어기지 않는다.
특히 성과 면에서 이 접근방식에 사소한/중대한 단점이 있는가?또한 이러한 접근 방식이 어디에서 유용하다고 생각하십니까?
당신이 꽤 정확하게 지적했듯이, Redex는 당신이 당신의 어플리케이션에서 어떤 일이 발생하는 지점과 이 이벤트를 반영하기 위해 실제로 스토어가 업데이트되는 지점 사이에 여러 계층의 양방향성을 구현하도록 요구한다.
이건 일부러 그런 거야.
글로벌 상태는 일반적으로 간단한 방법이나 이유를 이해하지 않고, 당신의 어플리케이션의 어느 곳에서든 임의로 변경될 수 있다는 문제를 만들어 낸다.그리고 그렇다, Redex 매장은 사실상 글로벌한 상태다.
(행동으로 표현되고 행위의 페이로드로 설명되는) 무엇이 일어났는지에 대한 질문들과 (환원기로 정의되는) 글로벌 상태에 어떻게 영향을 미치는가에 대한 질문을 분리함으로써, Redex는 어느 정도 이 문제를 제거한다.글로벌 상태에 대한 임의적인 변경을 허용하는 대신, 최상의 경우 변경 사항을 다시 원래 위치로 추적할 수 있을 만큼 충분한 의미 정보가 첨부되는 잘 정의된 이벤트에 의해 촉발된, 확실하고 매우 구체적인 변경 조합만 수행할 수 있다.
단일 쌍의 일반적인 작용과 환원기를 만들어 Redex의 핵심 아이디어를 손상시킴으로써, 당신은 Redex의 핵심 장점 중 하나를 느슨하게 하고, 당신의 부품과 가게 사이에 중요한 이점을 가져다 주지 않는 일련의 방해와 추상화를 남겨둔다.
가치를 창출하지 않는 코드가 가장 잘 삭제되는 코드라는 것은 상식이다.내 생각에, 당신은 Redex를 사용하지 않고 단순히 Redex의 무력한 구현을 사용하는 것보다 구성요소 상태를 사용하는 것이 훨씬 더 나을지도 모른다.
Redex를 만든 Dan Abramov가 쓴 이 주제에 대한 흥미로운 읽을거리: Redex가 필요하지 않을 수도 있다.
Timo의 대답은 왜 당신의 구현이 Redex의 많은 원칙에 어긋나는지를 설명하는 데 도움이 된다.나는 네가 Mobx가 흥미롭다고 생각할지도 모른다고 덧붙이고 싶다.나는 그것이 당신이 얻으려는 국가 경영의 종류와 더 밀접하게 닮았다고 생각한다.
이 함수(감속기에 의해 호출되는 할당)는 Redex 규칙에 따른 것이 아니며, 상태를 변이하기 때문에 불변의 '순수' 함수가 아니다.
테스트:
const assign = (obj, prop, value) => {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e], prop, value);
} else
obj[prop[0]] = value;
return obj
}
const reducer = (state, action) => {
if (action.type == 'SETTER') {
try {
return assign(state, action.data.target, action.data.value)
}
catch (err) {
console.log('WARNING: the key wasn\'t valid', err)
}
}
return state;
}
const testReducer = () => {
const user = {
id: 0,
name: ''
};
const action = {
type: 'SETTER',
data: {
target: 'name',
value: 'Roy'
}
};
console.log('user before: ', user);
reducer(user, action);
console.log('user after: ', user);
};
testReducer();
테스트 결과:
user before: { id: 0, name: '' }
user after: { id: 0, name: 'Roy' }
가장 쉬운 해결 방법:
const assign = (obj, prop, value) => {
var tempObj = Object.assign({}, obj);
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(tempObj[e], prop, value);
} else
tempObj[prop[0]] = value;
return tempObj
}
편집
대상 개체를 임시로 설정할 상태 개체의 값을 복사하지 않고 수정:
const assign = (obj, prop, value) => {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e], prop, value);
} else {
return {
...obj,
[prop[0]]: value
};
}
}
환원기는 이제 간단한 기능이며 쉽게 재사용할 수 있다.
const getData = (state, action) => {
return {...state, data: state.data.concat(action.payload)};
};
const removeLast = (state) => {
return {...state, data: state.data.filter(x=>x !== state.data[state.data.length-1])};
}
이제 조치 유형 및 환원기 기능이 배열로 선언됨
const actions = [
{type: 'GET_DATA', reducer: getData},
{type: 'REMOVE_LAST', reducer: removeLast},
{type: 'REMOVE_FIRST', reducer: removeFirst},
{type: 'REMOVE_ALL', reducer: removeAll},
{type: 'REMOVE_BY_INDEX', reducer: removeByIndex}
];
환원기의 초기 상태
const initialState = {
data: []
}
actionGenerators는 기호를 사용하여 고유한 Id를 생성하고 이 Id를 동작 및 감속기 기능에 할당한다.
const actionGenerators = (actions) => {
return actions.reduce((a,c)=>{
const id = Symbol(c.type);
a.actions = {...a.actions, [c.type]: id};
a.reducer = a.reducer ? a.reducer.concat({id, reducer: c.reducer}) : [{id, reducer: c.reducer}];
return a;
},{});
}
환원기생성기는 일반적인 환원기 제작자 입니다.
const reducerGenerators = (initialState, reducer) => {
return (state = initialState, action) => {
const found = reducer.find(x=>x.id === action.type);
return found ? found.reducer(state, action) : state;
}
}
사용법
const actionsReducerCreator = actionGenerators(actions);
const store = createStore(reducerGenerators(initialState, actionsReducerCreator.reducer));
const {GET_DATA} = actionsReducerCreator.actions;
store.dispatch({type: GET_DATA});
내 Github Reducx-Reducer-Generator의 작업관리 응용 프로그램에서 이것을 구현했다.
'programing' 카테고리의 다른 글
과학적 표기법 없이 정밀한 방법으로 숫자 배열로 예쁘게 인쇄하는 방법? (0) | 2022.04.03 |
---|---|
Reducx 라우터 - "Dispatch가 정의되지 않음" (0) | 2022.04.02 |
f-string을 사용한 소수점 이후의 고정 자리수 (0) | 2022.04.02 |
에픽에서 동일한 통화를 두 번 시작하는 것을 방지하는 방법 (0) | 2022.04.02 |
Vue Router에서 발송된 후 저장소 데이터를 올바르게 업데이트하지 마십시오. (0) | 2022.04.02 |