programing

react/redux에서 bindActionCreators는 언제 사용됩니까?

closeapi 2023. 3. 17. 21:31
반응형

react/redux에서 bindActionCreators는 언제 사용됩니까?

bindActionCreators대한 Redx docs의 스테이트는 다음과 같습니다.

의 예bindActionCreators일부 액션 크리에이터를 Redux를 인식하지 못하는 컴포넌트에 전달하고 디스패치나 Redux 스토어를 전달하고 싶지 않은 경우입니다.

요?bindActionCreators/필필????

Redux를 인식하지 못하는 구성 요소는 무엇입니까?

두 옵션의 장점/단점은 무엇입니까?

//actionCreator
import * as actionCreators from './actionCreators'

function mapStateToProps(state) {
  return {
    posts: state.posts,
    comments: state.comments
  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(actionCreators, dispatch)
}

function mapStateToProps(state) {
  return {
    posts: state.posts,
    comments: state.comments
  }
}

function mapDispatchToProps(dispatch) {
  return {
    someCallback: (postId, index) => {
      dispatch({
        type: 'REMOVE_COMMENT',
        postId,
        index
      })
    }
  }
}

나는 가장 인기 있는 답이 실제로 그 질문에 대한 것이라고 생각하지 않는다.

다음 예시는 모두 기본적으로 동일한 작업을 수행하며 "사전 바인딩" 개념을 따릅니다.

// option 1
const mapDispatchToProps = (dispatch) => ({
  action: () => dispatch(action())
})


// option 2
const mapDispatchToProps = (dispatch) => ({
  action: bindActionCreators(action, dispatch)
})


// option 3
const mapDispatchToProps = {
  action: action
}

★★#3는 입니다.#1에 왜 선택지를 사용해야 에 대한 진짜 질문입니다.#1 옵션 vs 옵 vs#2둘 다 react-redux 코드 베이스로 사용되고 있는 것을 본 적이 있습니다만, 조금 혼란스럽다고 생각합니다.

제 생각에 혼란은 에 나오는 모든 예들이react-redux은 " " 를 사용합니다.bindActionCreatorsbindActionCreators 문서(질문 자체에서 인용한 바와 같이)에서는 react-redux와 함께 사용하지 말라고 합니다.

코드 베이스의 일관성이 정답이라고 생각합니다만, 개인적으로는 필요할 때마다 디스패치 처리를 명시적으로 하는 것을 선호합니다.

99% React-Redux와 사용합니다.connect()의 기능합니다.mapDispatchToProps파라미터를 지정합니다.할 수 .mapDispatch 찬 를 에 connect.

이 아이디어는 작업 작성자를 미리 바인딩함으로써 전달되는 구성 요소를connect() 말하면 '', '모르겠다', '모르겠다', '모르겠다' 이렇게 죠.this.props.someCallback()크리에이터를 ,라고 하는 에는 . .크 . . . . . . . . . . . . . ..this.props.dispatch(someActionCreator()) 컴포넌트는되어 있습니다.props.dispatch존재하게 됩니다.

나는 블로그 투고 Idiomatic Redux: 액션 크리에이터를 사용하는가?에서 이 주제에 대한 생각을 썼다.

보다 완전한 예에서는 연결하기 위해 작업 작성자가 가득 찬 개체를 전달합니다.

import * as ProductActions from './ProductActions';

// component part
export function Product({ name, description }) {
    return <div>
        <button onClick={this.props.addProduct}>Add a product</button>
    </div>
}

// container part
function mapStateToProps(state) {
    return {...state};
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({
        ...ProductActions,
    }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Product);

원래의 질문에 답하도록 하겠습니다.

스마트 및 덤 컴포넌트

으로 '왜 그러느냐'고 물어봅니다.bindActionCreators어떤 컴포넌트가 Redux에 대해 인식해서는 안 되는지에 대해 설명합니다.

즉, 컴포넌트는 스마트(컨테이너) 컴포넌트와 바보(프레젠테이션) 컴포넌트로 분할해야 합니다.바보같은 컴포넌트는 니즈 투 알 베이스로 동작합니다.그들의 영혼의 일은 주어진 데이터를 HTML로만 렌더링하는 것이다.애플리케이션의 내부 동작에 대해 알고 있으면 안 됩니다.응용 프로그램의 피부 깊숙이 있는 전면 레이어로 볼 수 있습니다.

반면 스마트 컴포넌트는 일종의 접착제입니다.이는 멍청한 컴포넌트를 위한 데이터를 준비하고 HTML 렌더링을 하지 않는 것이 좋습니다.

이러한 아키텍처는 UI 계층과 데이터 계층 간의 느슨한 결합을 촉진합니다.이것에 의해, 2개의 레이어를 다른 레이어(즉, 새로운 UI 설계)로 간단하게 교환할 수 있어 다른 레이어가 파손되지 않습니다.

질문에 대한 답변: 멍청한 컴포넌트는 Redx(또는 데이터 레이어의 불필요한 구현 세부사항)를 인식할 수 없습니다.향후에는 다른 것으로 대체하고 싶어질 수 있습니다.

이 개념에 대한 자세한 내용은 Redux 매뉴얼과 Dan Abramov의 Presentational and Container Components 기사에서 자세히 확인할 수 있습니다.

어떤 예가 더 좋습니까?

두 번째 질문은 주어진 예제의 장점과 단점에 관한 것이었다.

번째 예에서는 작업 작성자가 별도로 정의됩니다.actionCreators 즉곳에서 할 수 .이것은 행동을 정의하는 표준적인 방법입니다.나는 이것에 대해 어떠한 단점도 별로 보이지 않는다.

두 번째 예에서는 액션작성자를 인라인으로 정의하고 있습니다.이 예에는 여러 가지 단점이 있습니다.

  • 작업 작성자를 재사용할 수 없습니다(사용할 수 없음).
  • 그것은 읽기 어려운 것으로 해석되는 보다 장황하다
  • 되어 있습니다.- 은 하드 코드화되어 있고, 코드화되어 있습니다.이것을 다음과 같이 정의하는 것이 바람직합니다.consts리듀서(로할 수 있도록 가 발생할 .에서 참조할 수 있도록 합니다.그러면 오타가 발생할 가능성이 줄어듭니다.
  • 액션 크리에이터를 인라인으로 정의하는 것은 권장/예상된 사용 방법에 반하는 것입니다.그러면 코드를 공유할 예정인 경우 커뮤니티에서 코드를 읽을 수 없게 됩니다.

두 번째 예제는 첫 번째 예보다 한 가지 장점이 있습니다. 바로 쓰기 속도입니다.따라서 코드에 대한 더 나은 계획이 없다면 문제 없을 수도 있습니다.

내가 좀 더 명확하게 해 줬으면 좋겠는데...

「 」를 할 수 있는 은, 「 」를 할 수 있습니다.bindActionCreators()여러 액션을 하나의 소품으로 "매핑"하는 것입니다.

통상적인 디스패치는 다음과 같습니다.

몇 가지 일반적인 사용자 액션을 소품에 매핑합니다.

const mapStateToProps = (state: IAppState) => {
  return {
    // map state here
  }
}
const mapDispatchToProps = (dispatch: Dispatch) => {
  return {
    userLogin: () => {
      dispatch(login());
    },
    userEditEmail: () => {
      dispatch(editEmail());
    },
  };
};
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

대규모 프로젝트에서는 각 디스패치를 개별적으로 매핑하는 것이 번거롭게 느껴질 수 있습니다.서로 관련된 일련의 액션이 있는 경우 이러한 액션을 조합할 수 있습니다.예를 들어, 모든 종류의 사용자 관련 작업을 수행한 사용자 작업 파일입니다.각 액션을 개별 디스패치라고 부르지 않고 사용할 수 있습니다.bindActionCreators()dispatch

bindActionCreators()를 사용한 여러 디스패치

관련된 모든 작업을 가져옵니다.모든 파일이 redux 스토어의 동일한 파일에 있을 수 있습니다.

import * as allUserActions from "./store/actions/user";

디스패치를 사용하는 대신 bindActionCreators()를 사용합니다.

    const mapDispatchToProps = (dispatch: Dispatch) => {
      return {
           ...bindActionCreators(allUserActions, dispatch);
        },
      };
    };
    export default connect(mapStateToProps, mapDispatchToProps, 
    (stateProps, dispatchProps, ownProps) => {
      return {
        ...stateProps,
        userAction: dispatchProps
        ownProps,
      }
    })(MyComponent);

할 수 되었습니다.userAction이치노

IE:userAction.login() userAction.editEmail() ★★★★★★★★★★★★★★★★★」this.props.userAction.login() this.props.userAction.editEmail().

.(: bindActionCreators()는 bindActionCreators()입니다.=> {return {}} that에 매핑되다userAction를 사용할 .bindActionCreators()단일 파일의 모든 작업을 개별 소품으로 매핑합니다.하지만 그렇게 하는 것은 혼란스러울 수 있습니다.저는 각각의 행동이나 "행동 그룹"에 명시적인 이름을 붙이는 것을 선호합니다.요.ownProps이 '어린이 소품'이 무엇인지, 어디서 왔는지 좀 더 자세히 설명해 주세요.Redux + React를 사용하면 모든 소품이 어디에 공급되고 있는지 혼란스러울 수 있으므로 설명 내용이 많을수록 좋습니다.

를 사용하여bindActionCreators덤 컴포넌트)를할 수

// actions.js

export const increment = () => ({
    type: 'INCREMENT'
})

export const decrement = () => ({
    type: 'DECREMENT'
})
// main.js
import { Component } from 'react'
import { bindActionCreators } from 'redux'
import * as Actions from './actions.js'
import Counter from './counter.js'

class Main extends Component {

  constructor(props) {
    super(props);
    const { dispatch } = props;
    this.boundActionCreators = bindActionCreators(Actions, dispatch)
  }

  render() {
    return (
      <Counter {...this.boundActionCreators} />
    )
  }
}
// counter.js
import { Component } from 'react'

export default Counter extends Component {
  render() {
    <div>
     <button onclick={() => this.props.increment()}
     <button onclick={() => this.props.decrement()}
    </div>
  }
}

bindActionsCreators에 대해 자세히 알아보려고 했는데, 이것이 제가 프로젝트에서 구현한 방법입니다.

// Actions.js
// Action Creator
const loginRequest = (username, password) => {
 return {
   type: 'LOGIN_REQUEST',
   username,
   password,
  }
}

const logoutRequest = () => {
 return {
   type: 'LOGOUT_REQUEST'
  }
}

export default { loginRequest, logoutRequest };

리액트 컴포넌트

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ActionCreators from './actions'

class App extends Component {
  componentDidMount() {
   // now you can access your action creators from props.
    this.props.loginRequest('username', 'password');
  }

  render() {
    return null;
  }
}

const mapStateToProps = () => null;

const mapDispatchToProps = dispatch => ({ ...bindActionCreators(ActionCreators, dispatch) });

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(App);

작업 작성자를 바인딩하는 유일한 사용 사례는 일부 작업 작성자를 Redex를 인식하지 못하는 구성요소로 전달하려는 경우입니다. 이렇게 해서 제가 수 .useActions 삭제:

import { useDispatch } from "react-redux";
import { bindActionCreators } from "redux";
// I exported all the actions as actionCreators
// export * as actionCreators from "./action-creators";
import { actionCreators } from "../state";

export const useActions = () => {
  const dispatch = useDispatch();
  return bindActionCreators(actionCreators, dispatch);
};

actionCreators는 파일에서 모두 내보낸 액션 크리에이터 함수입니다.예를 들어 updatePost 작업 생성자가 있다고 가정합니다.

export const updatePost = (id: string, content: string): UpdatePostAction => {
  return { type: ActionType.UPDATE_POST, payload: { id, content } };
};

따라서 update Post 액션을 디스패치할 때마다 다음과 같이 기술합니다.

const {updatePost}=useActions()
updatePost({id,content})

의의 の 1 case case case case의 좋은 예:bindActionCreators는, redex-superval-superval을 사용하는 redux-superval과 통합하기 위한 것입니다.예를 들어 다음과 같습니다.

// routines.js
import { createRoutine } from "redux-saga-routines";
export const fetchPosts = createRoutine("FETCH_POSTS");
// Posts.js
import React from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { fetchPosts } from "routines";

class Posts extends React.Component {
  componentDidMount() {
    const { fetchPosts } = this.props;
    fetchPosts();
  }

  render() {
    const { posts } = this.props;
    return (
      <ul>
        {posts.map((post, i) => (
          <li key={i}>{post}</li>
        ))}
      </ul>
    );
  }
}

const mapStateToProps = ({ posts }) => ({ posts });
const mapDispatchToProps = dispatch => ({
  ...bindActionCreators({ fetchPosts }, dispatch)
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Posts);
// reducers.js
import { fetchPosts } from "routines";

const initialState = [];

export const posts = (state = initialState, { type, payload }) => {
  switch (type) {
    case fetchPosts.SUCCESS:
      return payload.data;
    default:
      return state;
  }
};
// api.js
import axios from "axios";

export const JSON_OPTS = { headers: { Accept: "application/json" } };
export const GET = (url, opts) =>
  axios.get(url, opts).then(({ data, headers }) => ({ data, headers }));
// sagas.js
import { GET, JSON_OPTS } from "api";
import { fetchPosts } from "routines";
import { call, put, takeLatest } from "redux-saga/effects";

export function* fetchPostsSaga() {
  try {
    yield put(fetchPosts.request());
    const { data } = yield call(GET, "/api/posts", JSON_OPTS);
    yield put(fetchPosts.success(data));
  } catch (error) {
    if (error.response) {
      const { status, data } = error.response;
      yield put(fetchPosts.failure({ status, data }));
    } else {
      yield put(fetchPosts.failure(error.message));
    }
  } finally {
    yield put(fetchPosts.fulfill());
  }
}

export function* fetchPostsRequestSaga() {
  yield takeLatest(fetchPosts.TRIGGER, fetchPostsSaga);
}

이 패턴은 React Hooks(React 16.8 기준)를 사용하여 구현할 수 있습니다.

docs 문장은 매우 명확합니다.

의 예bindActionCreators일부 액션 크리에이터를 Redux를 인식하지 못하는 컴포넌트에 전달하고 디스패치나 Redux 스토어를 전달하고 싶지 않은 경우입니다.

이는 분명히 다음과 같은 한 가지 조건에서만 발생할 수 있는 사용 사례입니다.

컴포넌트 A와 B가 있다고 칩시다.

// A use connect and updates the redux store
const A = props => {}
export default connect()(A)

// B doesn't use connect therefore it does not know about the redux store.
const B = props => {}
export default B

리액트 리덕스에 주입: (A)

const boundActionCreators = bindActionCreators(SomeActionCreator, dispatch)
// myActionCreatorMethod,
// myActionCreatorMethod2,
// myActionCreatorMethod3,

// when we want to dispatch
const action = SomeActionCreator.myActionCreatorMethod('My updates')
dispatch(action)

react-redux 주입: (B)

const { myActionCreatorMethod } = props
<B myActionCreatorMethod={myActionCreatorMethod} {...boundActionCreators} />

다음 사항에 대해 알고 계십니까?

  • 컴포넌트 B에 레덕스 스토어가 있는지 알 수 없는 상태에서 컴포넌트 A를 통해 레덕스 스토어를 업데이트했습니다.

  • A 컴포넌트에서는 업데이트를 하고 있지 않습니다.제 말이 무슨 뜻인지 정확히 알고 싶으시다면, 게시물을 살펴보시면 됩니다.좋은 생각이 있으시기를 바랍니다.

언급URL : https://stackoverflow.com/questions/41754489/when-would-bindactioncreators-be-used-in-react-redux

반응형