내가 다음을 가지고 있다고 가정 해보십시오.
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
}
}
그리고 그 액션 크리에이터에서 글로벌 스토어 상태 (모든 리듀서)에 액세스하고 싶습니다. 이것을하는 것이 낫습니다 :
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
아니면 이거:
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return (dispatch, getState) => {
const {items} = getState().otherReducer;
dispatch(anotherAction(items));
}
}
답변
활동중인 작성자의 상태에 액세스하는 것이 좋은 아이디어인지에 대해 다른 의견이 있습니다.
- Redux 제작자 Dan Abramov는 다음과 같이 제한적이라고 생각합니다. “허용되는 것으로 생각되는 몇 가지 사용 사례는 요청하기 전에 캐시 된 데이터를 확인하거나 인증 여부 (즉, 조건부 디스패치)를 확인하는 것입니다. 나는 지나가는 생각 데이터 등
state.something.items
이 버그와 경우 : 액션 작성자의 것은 확실히 안티 패턴이며이 변경 기록을 가려 때문에 권장하지 않습니다items
잘못, 그것을 추적하기 어려운 경우 그 잘못된 값들이 있기 때문에 출신 조치에 대한 응답으로 감속기에 의해 직접 계산되는 것이 아니라 이미 조치의 일부입니다. “ - 현재의 Redux 관리자 인 마크 에릭슨 (Mark Erikson)은이 기능이 훌륭하고
getState
썽크 에 사용하도록 권장 한다고 말합니다 . 그는 블로그 게시물 Idiomatic Redux : Thunks, Sagas, Abstraction, and Reusability에 대한 생각 에서 액션 제작자 상태 액세스의 장단점에 대해 설명합니다 .
이것이 필요하다는 것을 알게되면 제안한 두 가지 접근법이 모두 좋습니다. 첫 번째 접근 방식에는 미들웨어가 필요하지 않습니다.
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
그러나 store
일부 모듈에서 내 보낸 싱글 톤 에 의존한다는 것을 알 수 있습니다 . 대부분의 경우 서버마다 요청마다 별도의 저장소를 원하기 때문에 앱에 서버 렌더링 을 추가 하는 것이 훨씬 어렵 기 때문에 권장하지 않습니다 . 따라서이 방법이 기술적으로 작동하는 동안 모듈에서 상점을 내보내는 것은 권장하지 않습니다.
이것이 두 번째 접근법을 권장하는 이유입니다.
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return (dispatch, getState) => {
const {items} = getState().otherReducer;
dispatch(anotherAction(items));
}
}
Redux Thunk 미들웨어를 사용해야하지만 클라이언트와 서버 모두에서 잘 작동합니다. Redux Thunk에 대한 자세한 내용 과이 경우 왜 필요한지 여기를 참조하십시오 .
이상적으로는, 당신의 행동이 “뚱뚱”해서는 안되며 가능한 적은 정보를 포함해야하지만, 자신의 응용 프로그램에서 가장 적합한 것을 자유롭게 할 수 있습니다. 돌아 오는 자주 묻는 질문에 대한 정보가 액션 제작자와 감속기 사이의 분할 논리 와 그것을 사용하는 것이 유용 할 수 있습니다 때 시간을 getState
액션 창조자에서 .
답변
시나리오가 간단하면 사용할 수 있습니다
import store from '../store';
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
items: store.getState().otherReducer.items,
}
}
그러나 때로는 action creator
여러 행동을 유발해야
예를 들어 비동기 요청이므로 REQUEST_LOAD
REQUEST_LOAD_SUCCESS
REQUEST_LOAD_FAIL
조치 가 필요합니다.
export const [REQUEST_LOAD, REQUEST_LOAD_SUCCESS, REQUEST_LOAD_FAIL] = [`REQUEST_LOAD`
`REQUEST_LOAD_SUCCESS`
`REQUEST_LOAD_FAIL`
]
export function someAction() {
return (dispatch, getState) => {
const {
items
} = getState().otherReducer;
dispatch({
type: REQUEST_LOAD,
loading: true
});
$.ajax('url', {
success: (data) => {
dispatch({
type: REQUEST_LOAD_SUCCESS,
loading: false,
data: data
});
},
error: (error) => {
dispatch({
type: REQUEST_LOAD_FAIL,
loading: false,
error: error
});
}
})
}
}
참고 : 액션 제작자에서 함수를 반환 하려면 redux-thunk 가 필요합니다 .
답변
@Bloomca에 동의합니다. 상점에서 필요한 값을 전달 기능으로 인수로 전달하는 것은 상점을 내보내는 것보다 간단합니다. 나는 여기에 예를 만들었다.
import React from "react";
import {connect} from "react-redux";
import * as actions from '../actions';
class App extends React.Component {
handleClick(){
const data = this.props.someStateObject.data;
this.props.someDispatchFunction(data);
}
render(){
return (
<div>
<div onClick={ this.handleClick.bind(this)}>Click Me!</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return { someStateObject: state.someStateObject };
};
const mapDispatchToProps = (dispatch) => {
return {
someDispatchFunction:(data) => { dispatch(actions.someDispatchFunction(data))},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
답변
상점에서 읽는 것이 그렇게 나쁘지는 않다는 점을 지적하고 싶습니다. 모든 것을 구성 요소에 전달 한 다음 매개 변수로 저장하는 것보다 상점을 기반으로 수행해야 할 작업을 결정하는 것이 훨씬 더 편리 할 수 있습니다 기능. 클라이언트 측 렌더링에만 사용한다고 100 % 확신하지 않는 한 (단, 버그 추적이 어려울 수 있음) 단단하지 않은 경우 상점을 단일 톤으로 사용하지 않는 것이 훨씬 낫다는 Dan의 의견에 전적으로 동의합니다.
최근에 redux의 세부 정보를 다루기 위해 라이브러리를 만들었 으며 미들웨어에 모든 것을 넣는 것이 좋습니다.
따라서 귀하의 예는 다음과 같습니다.
import { createSyncTile } from 'redux-tiles';
const someTile = createSyncTile({
type: ['some', 'tile'],
fn: ({ params, selectors, getState }) => {
return {
data: params.data,
items: selectors.another.tile(getState())
};
},
});
그러나 보시다시피 여기서 데이터를 실제로 수정하지는 않으므로 다른 곳 에서이 선택기를 사용하여 다른 곳에서 결합 할 수있는 좋은 기회가 있습니다.
답변
이를 해결하는 다른 방법을 제시합니다. 응용 프로그램에 따라 Dan의 솔루션보다 낫거나 나쁠 수 있습니다.
액션을 두 개의 개별 기능으로 분할하여 리듀서에서 상태를 액션으로 가져올 수 있습니다. 먼저 데이터 요청, 두 번째 데이터 작업. 를 사용하여 그렇게 할 수 있습니다 redux-loop
.
먼저 ‘친절하게 데이터를 요청하십시오’
export const SOME_ACTION = 'SOME_ACTION';
export function someAction() {
return {
type: SOME_ACTION,
}
}
감속기에서 요청을 가로 채고를 사용하여 데이터를 2 단계 조치에 제공하십시오 redux-loop
.
import { loop, Cmd } from 'redux-loop';
const initialState = { data: '' }
export default (state=initialState, action) => {
switch(action.type) {
case SOME_ACTION: {
return loop(state, Cmd.action(anotherAction(state.data))
}
}
}
손에 든 데이터를 사용하여 처음에 원하는 것을 수행하십시오.
export const ANOTHER_ACTION = 'ANOTHER_ACTION';
export function anotherAction(data) {
return {
type: ANOTHER_ACTION,
payload: data,
}
}
이것이 누군가를 돕기를 바랍니다.
답변
나는 여기서 파티에 늦었다는 것을 알고 있지만, 행동에 국가를 사용하려는 내 자신의 욕구에 대한 의견을 여기에 왔으며, 내가 올바른 행동이라고 생각하는 것을 깨달았을 때 내 자신을 형성했습니다.
이것은 선택자가 나에게 가장 적합한 곳입니다. 이 요청을 발행 한 구성 요소는 선택을 통해 발행 할시기가되어야합니다.
export const SOME_ACTION = 'SOME_ACTION';
export function someAction(items) {
return (dispatch) => {
dispatch(anotherAction(items));
}
}
추상화가 유출되는 것처럼 느껴질 수 있지만 구성 요소는 메시지를 명확하게 보내야하며 메시지 페이로드에는 관련 상태가 포함되어야합니다. 불행히도 귀하의 질문에는 선택기 및 동작의 ‘더 나은 모델’을 사용할 수 있기 때문에 구체적인 예가 없습니다.
답변
나는 가장 깨끗한 것을 찾을 수있는 또 다른 대안을 제안하고 싶지만, react-redux
또는 비슷한 것이 필요합니다. 또한 그 과정에서 다른 멋진 기능을 사용하고 있습니다.
// actions.js
export const someAction = (items) => ({
type: 'SOME_ACTION',
payload: {items},
});
// Component.jsx
import {connect} from "react-redux";
const Component = ({boundSomeAction}) => (<div
onClick={boundSomeAction}
/>);
const mapState = ({otherReducer: {items}}) => ({
items,
});
const mapDispatch = (dispatch) => bindActionCreators({
someAction,
}, dispatch);
const mergeProps = (mappedState, mappedDispatches) => {
// you can only use what gets returned here, so you dont have access to `items` and
// `someAction` anymore
return {
boundSomeAction: () => mappedDispatches.someAction(mappedState.items),
}
});
export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);
// (with other mapped state or dispatches) Component.jsx
import {connect} from "react-redux";
const Component = ({boundSomeAction, otherAction, otherMappedState}) => (<div
onClick={boundSomeAction}
onSomeOtherEvent={otherAction}
>
{JSON.stringify(otherMappedState)}
</div>);
const mapState = ({otherReducer: {items}, otherMappedState}) => ({
items,
otherMappedState,
});
const mapDispatch = (dispatch) => bindActionCreators({
someAction,
otherAction,
}, dispatch);
const mergeProps = (mappedState, mappedDispatches) => {
const {items, ...remainingMappedState} = mappedState;
const {someAction, ...remainingMappedDispatch} = mappedDispatch;
// you can only use what gets returned here, so you dont have access to `items` and
// `someAction` anymore
return {
boundSomeAction: () => someAction(items),
...remainingMappedState,
...remainingMappedDispatch,
}
});
export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);
당신이 다시 사용하려는 경우 특정을 추출해야합니다 mapState
, mapDispatch
그리고 mergeProps
기능에 다른 곳에서 재사용 할 수 있지만,이 차종은 완벽하게 명확한 종속성.