Подтвердить что ты не робот

Когда будет использоваться bindActionCreators в реакции/сокращении?

Документы Redux для bindActionCreators гласят:

Единственный вариант использования 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
      })
    }
  }
}
4b9b3361

Ответ 1

99% времени, он используется с функцией React-Redux connect(), как часть параметра mapDispatchToProps. Он может использоваться явно внутри предоставляемой вами функции mapDispatch или автоматически, если вы используете синтаксис сокращенного объекта и передаете объект, полный создателей действия, в connect.

Идея заключается в том, что, предварительно привязывая создателей действия, компонент, который вы передаете connect() технически "не знает", что он подключен, - он просто знает, что ему нужно запустить this.props.someCallback(). С другой стороны, если вы не связывали создателей действий и вызывали this.props.dispatch(someActionCreator()), теперь компонент "знает", что он связан, потому что он ожидает существования props.dispatch.

Я написал некоторые мысли по этой теме в своем сообщении в блоге Idiomatic Redux: зачем использовать создателей действий?.

Ответ 2

Я не думаю, что самый популярный ответ, на самом деле адресует вопрос.

Все приведенные ниже примеры, по сути, делают одно и то же и следуют принципу "без предварительной привязки".

// 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 против варианта #2. Я видел, как они оба использовались в коде Resase-Redux, и я нахожу это довольно запутанным.

Я думаю, что путаница происходит из того факта, что все примеры в react-redux документ использует bindActionCreators в то время как документ для bindActionCreators (как указано в самом вопросе) говорит, чтобы не использовать его с среагировать-Redux.

Я предполагаю, что ответ заключается в согласованности в кодовой базе, но я лично предпочитаю явно оборачивать действия в диспетчере всякий раз, когда это необходимо.

Ответ 3

Более полный пример, передайте объект, полный создателей действия для подключения:

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);

Ответ 4

Я постараюсь ответить на оригинальные вопросы...

Smart & Dumb компоненты

В своем первом вопросе вы в основном спрашиваете, зачем в первую очередь нужен bindActionCreators и какие компоненты не должны знать о Redux.

Короче говоря, идея заключается в том, что компоненты должны быть разделены на умные (контейнерные) и тупые (презентационные) компоненты. Тупые компоненты работают по мере необходимости. Их работа состоит в том, чтобы преобразовывать данные в HTML и ничего более. Они не должны знать о внутренней работе приложения. Их можно рассматривать как глубокий передний слой кожи вашего приложения.

С другой стороны, интеллектуальные компоненты являются своего рода клеем, который подготавливает данные для немых компонентов и предпочтительно не выполняет рендеринг HTML.

Такая архитектура способствует слабой связи между уровнем пользовательского интерфейса и уровнем данных под ним. Это, в свою очередь, позволяет легко заменить любой из двух слоев чем-то другим (например, новым дизайном пользовательского интерфейса), что не сломает другой слой.

Чтобы ответить на ваш вопрос: глупые компоненты не должны знать о Redux (или о каких-либо ненужных деталях реализации уровня данных в этом отношении), потому что мы могли бы захотеть заменить его чем-то другим в будущем.

Вы можете узнать больше об этой концепции в руководстве Redux, а также в статье Презентационные и Контейнерные компоненты Дана Абрамова.

Какой пример лучше

Второй вопрос касался преимуществ/недостатков приведенных примеров.

В первом примере создатели действий определены в отдельном файле/модуле actionCreators, что означает, что они могут быть использованы в другом месте. Это в значительной степени стандартный способ определения действий. Я действительно не вижу никаких недостатков в этом.

Второй пример определяет создателей действий, которые имеют ряд недостатков:

  • создатели действий не могут быть повторно использованы (очевидно)
  • вещь более многословна, что означает менее читабельный
  • Типы действий жестко запрограммированы - желательно определять их как consts отдельно, чтобы на них можно было ссылаться в редукторах - это уменьшило бы вероятность опечаток
  • определение встроенных действий создателей противоречит рекомендованному/ожидаемому способу их использования, что сделает ваш код менее читабельным для сообщества, если вы планируете поделиться своим кодом

Второй пример имеет одно преимущество перед первым - это быстрее писать! Так что если у вас нет больших планов для вашего кода, это может быть просто хорошо.

Надеюсь, мне удалось кое-что прояснить...

Ответ 5

используя bindActionCreators, он может сгруппировать несколько функций действия и передать их компоненту, который не знает о Redux (тупой компонент), как это так

// 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>
  }
}

Ответ 6

Один хороший пример использования для bindActionCreators - для интеграции с redux-saga с использованием redux-saga-рутин. Например:

// 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).

Ответ 7

Я также хотел узнать больше о 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 };

В вашем React компоненте

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);

Ответ 8

Одним из возможных применений 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()

Импортируйте все ваши связанные действия. Скорее всего, они находятся в одном и том же файле в магазине приставок.

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() с одним реквизитом. (Дополнительный => {return {}} который отображается на userAction). Вы также можете использовать bindActionCreators() чтобы отобразить все действия одного файла как отдельные объекты. Но я считаю, что это может сбивать с толку. Я предпочитаю, чтобы каждому действию или "группе действий" давалось явное имя. Мне также нравится называть ownProps более подробно о том, что это за "дочерние реквизиты" или откуда они ownProps. При использовании Redux + React может возникнуть некоторая путаница в отношении того, где поставляются все реквизиты, поэтому, чем больше описаний, тем лучше.

Ответ 9

Заявление документов очень ясно:

Единственный вариант использования 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)

Вводится с помощью реакции-редукса: (B)

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

Заметили следующее?

  • Мы обновили хранилище избыточности через компонент А, пока мы не знали о хранилище избыточности в компоненте В.

  • Мы не обновляем компонент А. Чтобы узнать, что именно я имею в виду, вы можете изучить этот пост. Я надеюсь, что у вас есть идея.