리듀서로 액션을 디스패치할 수 있습니까?
리듀서 자체에 액션을 디스패치할 수 있습니까?프로그레스바와 오디오 요소가 있습니다.목표는 오디오 요소에서 시간이 업데이트될 때 진행 표시줄을 업데이트하는 것입니다.그러나 ontimeupdate 이벤트 핸들러를 어디에 배치해야 하는지, 또는 ontimeupdate 콜백에 액션을 디스패치하여 프로그레스바를 갱신해야 하는지 알 수 없습니다.코드는 다음과 같습니다.
//reducer
const initialState = {
audioElement: new AudioElement('test.mp3'),
progress: 0.0
}
initialState.audioElement.audio.ontimeupdate = () => {
console.log('progress', initialState.audioElement.currentTime/initialState.audioElement.duration);
//how to dispatch 'SET_PROGRESS_VALUE' now?
};
const audio = (state=initialState, action) => {
switch(action.type){
case 'SET_PROGRESS_VALUE':
return Object.assign({}, state, {progress: action.progress});
default: return state;
}
}
export default audio;
리듀서가 종료되기 전에 다른 디스패치를 기동하는 것은 안티패턴입니다리듀서 처음에 수신한 상태는 리듀서가 종료되었을 때 현재 어플리케이션 상태가 아니기 때문입니다.단, 리듀서 내에서 다른 디스패치를 스케줄 하는 것은 안티패턴이 아닙니다.사실 이것이 Elm 언어가 하는 일입니다.Redux는 아시다시피 Elm 아키텍처를 JavaScript에 도입하기 위한 시도입니다.
다음은 속성을 추가할 미들웨어입니다.asyncDispatch
당신의 모든 행동에 대해서요.리듀서가 완료되어 새로운 애플리케이션 상태가 반환되면asyncDispatch
트리거하다store.dispatch
어떤 행동을 취하든 상관없습니다.
// This middleware will just add the property "async dispatch" to all actions
const asyncDispatchMiddleware = store => next => action => {
let syncActivityFinished = false;
let actionQueue = [];
function flushQueue() {
actionQueue.forEach(a => store.dispatch(a)); // flush queue
actionQueue = [];
}
function asyncDispatch(asyncAction) {
actionQueue = actionQueue.concat([asyncAction]);
if (syncActivityFinished) {
flushQueue();
}
}
const actionWithAsyncDispatch =
Object.assign({}, action, { asyncDispatch });
const res = next(actionWithAsyncDispatch);
syncActivityFinished = true;
flushQueue();
return res;
};
이제 리듀서가 다음을 수행할 수 있습니다.
function reducer(state, action) {
switch (action.type) {
case "fetch-start":
fetch('wwww.example.com')
.then(r => r.json())
.then(r => action.asyncDispatch({ type: "fetch-response", value: r }))
return state;
case "fetch-response":
return Object.assign({}, state, { whatever: action.value });;
}
}
리듀서 내에서 액션을 디스패치하는 것은 안티패턴입니다리덕터는 부작용 없이 액션페이로드를 다이제스트하고 새 상태 개체를 반환하는 것입니다.리듀서 내에서 리스너를 추가하고 액션을 디스패치하면 액션 연쇄 및 기타 부작용이 발생할 수 있습니다.
초기화된 것 같습니다.AudioElement
클래스 및 이벤트청취자는 상태가 아닌 컴포넌트 내에 속합니다.이벤트 리스너 내에서 액션을 디스패치할 수 있습니다.이것은 갱신됩니다.progress
의 상태로.
다음 중 하나를 초기화할 수 있습니다.AudioElement
클래스 객체를 새 React 컴포넌트에 포함하거나 해당 클래스를 React 컴포넌트로 변환합니다.
class MyAudioPlayer extends React.Component {
constructor(props) {
super(props);
this.player = new AudioElement('test.mp3');
this.player.audio.ontimeupdate = this.updateProgress;
}
updateProgress () {
// Dispatch action to reducer with updated progress.
// You might want to actually send the current time and do the
// calculation from within the reducer.
this.props.updateProgressAction();
}
render () {
// Render the audio player controls, progress bar, whatever else
return <p>Progress: {this.props.progress}</p>;
}
}
class MyContainer extends React.Component {
render() {
return <MyAudioPlayer updateProgress={this.props.updateProgress} />
}
}
function mapStateToProps (state) { return {}; }
return connect(mapStateToProps, {
updateProgressAction
})(MyContainer);
주의:updateProgressAction
로 자동 포장됩니다.dispatch
디스패치에 직접 전화할 필요는 없습니다.
리플렉스가 같은 도서관을 이용해보세요.이를 통해 비동기 함수의 시퀀스 처리, 실행 중지, 지연 사용 등을 매우 깔끔하게 수행할 수 있습니다.그것은 매우 강력합니다!
redux-loop은 Elm에서 힌트를 얻어 이 패턴을 제공합니다.
기술적으로 어떤 것이든 가능하기 때문에, 당신은 그것을 할 수 있습니다.하지만 당신은 그것을 하지 말아야 한다.
다음은 Dan Abramov(Redux의 제작자)의 말을 인용한 것입니다.
"리듀서 내부에 왜 디스패치를 원하십니까?그것은 도서관을 심하게 오용하고 있다.이는 React에서 setState inside 렌더링을 허용하지 않는 것과 정확히 동일합니다."
자신이 직접 만든 '감축기 안에서 온 금단 파견' 기투브 티켓에서
리듀서 내부에서 디스패치 및 액션이 발생하는 것 같다.
가 간단한 .useReducer
인크루세
에서는, 「INCREASE 되어 「SUB 되어 「INCREASE」를 설정해 .cnt
로 하고 , 「INCRESE해, 「INCRESE」를 설정합니다.cnt
INCRESE무시되었습니다)0인크레스하다, -1번이다.
참조: https://codesandbox.io/s/simple-react-context-example-forked-p7po7?file=/src/index.http:syslog-http:syslogs
let listener = () => {
console.log("test");
};
const middleware = (action) => {
console.log(action);
if (action.type === "INCREASE") {
listener();
}
};
const counterReducer = (state, action) => {
middleware(action);
switch (action.type) {
case "INCREASE":
return {
...state,
cnt: state.cnt + action.payload
};
case "SUB":
return {
...state,
cnt: state.cnt - action.payload
};
default:
return state;
}
};
const Test = () => {
const { cnt, increase, substract } = useContext(CounterContext);
useEffect(() => {
listener = substract;
});
return (
<button
onClick={() => {
increase();
}}
>
{cnt}
</button>
);
};
{type: "INCREASE", payload: 1}
{type: "SUB", payload: 1}
// expected: cnt: 0
// cnt = -1
언급URL : https://stackoverflow.com/questions/36730793/can-i-dispatch-an-action-in-reducer
'itsource' 카테고리의 다른 글
'버튼' 대화형 역할을 수정하는 방법은 초점을 맞출 수 있어야 합니다. (0) | 2023.03.23 |
---|---|
(Angularj) 웹 어플리케이션 통합 테스트 방법 (0) | 2023.03.23 |
WooCommerce 2.2+에 번역 파일을 수동으로 설치하는 방법 (0) | 2023.03.18 |
리포지토리가 깨끗하지 않습니다.Angular 8에서 업데이트하기 전에 변경 사항을 커밋하거나 저장하십시오. (0) | 2023.03.18 |
스프링 부트 REST 응용 프로그램에서 Firebase를 사용하는 방법 (0) | 2023.03.18 |