Понимание React-Redux и mapStateToProps()

Я пытаюсь понять метод подключения к реактиву-редуксу и функции, которые он принимает в качестве параметров. В частности mapStateToProps().

Насколько я понимаю, возвращаемое значение mapStateToProps будет объектом, полученным из состояния (как оно хранится в хранилище), ключи которого будут переданы целевому компоненту (к которому применяется компонент connect) в качестве подпорок.

Это означает, что состояние, используемое вашим целевым компонентом, может иметь совершенно отличную структуру от состояния, которое хранится в вашем магазине.

Q: это нормально?
Q: это ожидается?
В: Это анти-паттерн?

+195
источник поделиться
7 ответов

Q: Is this ok?
A: да

Q: Is this expected?
Да, это ожидаемо (если вы используете реаги-редукс).

В: Is this an anti-pattern?
A: Нет, это не анти-паттерн.

Это называется "подключение" вашего компонента или "сделать его умным". Это по замыслу.

Это позволяет вам отделить ваш компонент от вашего состояния на дополнительное время, что увеличивает модульность вашего кода. Это также позволяет вам упростить состояние вашего компонента как подмножество состояния вашего приложения, что фактически помогает вам соответствовать шаблону Redux.

Подумайте об этом так: магазин должен содержать все состояние вашего приложения.
Для больших приложений это может содержать десятки свойств, вложенных во многие слои.
Вы не хотите тратить все это на каждый звонок (дорого).

Без mapStateToProps или какого-либо его аналога у вас возникнет соблазн поднять ваше состояние еще одним способом повышения производительности/упрощения.

+50
источник

Да, это правильно. Это просто вспомогательная функция, чтобы иметь более простой способ доступа к вашим свойствам состояния

Представьте, что у вас есть ключ posts в вашем приложении state.posts

state.posts //
/*    
{
  currentPostId: "",
  isFetching: false,
  allPosts: {}
}
*/

И составляющие Posts

По умолчанию connect()(Posts) сделает все реквизиты состояния доступными для подключенного компонента.

const Posts = ({posts}) => (
  <div>
    {/* access posts.isFetching, access posts.allPosts */}
  </div> 
)

Теперь, когда вы сопоставляете state.posts с вашим компонентом, он становится немного лучше

const Posts = ({isFetching, allPosts}) => (
  <div>
    {/* access isFetching, allPosts directly */}
  </div> 
)

connect(
  state => state.posts
)(Posts)

mapDispatchToProps

обычно вы должны написать dispatch(anActionCreator())

с bindActionCreators вы можете сделать это также легче, как

connect(
  state => state.posts,
  dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)
)(Posts)

Теперь вы можете использовать его в своем компоненте

const Posts = ({isFetching, allPosts, fetchPosts, deletePost }) => (
  <div>
    <button onClick={() => fetchPosts()} />Fetch posts</button>
    {/* access isFetching, allPosts directly */}
  </div> 
)

Обновление на actionCreators..

Пример действия actionCreator: deletePost

const deletePostAction = (id) => ({
  action: 'DELETE_POST',
  payload: { id },
})

Таким образом, bindActionCreators просто выполнит ваши действия, включит их в dispatch вызов. (Я не читал исходный код Redux, но реализация может выглядеть примерно так:

const bindActionCreators = (actions, dispatch) => {
  return Object.keys(actions).reduce(actionsMap, actionNameInProps => {
    actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))
    return actionsMap;
  }, {})
}
+111
источник
другие ответы

Связанные вопросы


Похожие вопросы

Вы правильно поняли первую часть:

Да, mapStateToProps имеет состояние Store в качестве аргумента/параметра (предоставляемого react-redux::connect) и используется для связывания компонента с определенной частью состояния хранилища.

Под связыванием я подразумеваю, что объект, возвращенный mapStateToProps будет предоставлен во время построения в качестве реквизита, и любое последующее изменение будет доступно через componentWillReceiveProps.

Если вы знаете шаблон проектирования Observer, то это точно такой же или небольшой вариант.

Пример поможет прояснить ситуацию:

import React, {
    Component,
} from 'react-native';

class ItemsContainer extends Component {
    constructor(props) {
        super(props);

        this.state = {
            items: props.items, //provided by [email protected]
            filteredItems: this.filterItems(props.items, props.filters),
        };
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            filteredItems: this.filterItems(this.state.items, nextProps.filters),
        });
    }

    filterItems = (items, filters) => { /* return filtered list */ }

    render() {
        return (
            <View>
                // display the filtered items
            </View>
        );
    }
}

module.exports = connect(
    //mapStateToProps,
    (state) => ({
        items: state.App.Items.List,
        filters: state.App.Items.Filters,
        //the State.App & state.App.Items.List/Filters are reducers used as an example.
    })
    // mapDispatchToProps,  that another subject
)(ItemsContainer);

Может быть другой реагирующий компонент с именем itemsFilters который обрабатывает отображение и сохраняет состояние фильтра в состоянии Redux Store, демонстрационный компонент "слушает" или "подписывается" на фильтры состояния Redux Store, поэтому всякий раз, когда фильтры сохраняют состояние (с помощью filtersComponent) response-redux обнаруживает, что произошло изменение, и уведомляет или "публикует" все прослушивающие/подписанные компоненты, отправляя изменения в их componentWillReceiveProps который в этом примере вызовет повторный фильтр элементов и обновит отображение в связи с тем, что реагирует состояние изменилось.

Дайте мне знать, если пример сбивает с толку или недостаточно ясен, чтобы дать лучшее объяснение.

Что касается: Это означает, что состояние, используемое вашим целевым компонентом, может иметь совершенно отличную структуру от состояния, которое хранится в вашем магазине.

Я не получил вопрос, но просто знаю, что состояние реакции (this.setState) полностью отличается от состояния магазина Redux!

Состояние реакции используется для обработки перерисовки и поведения компонента реакции. Состояние реакции содержится исключительно для компонента.

Состояние Redux Store представляет собой комбинацию состояний редукторов Redux, каждое из которых отвечает за управление небольшой частью логики приложения. Эти атрибуты редукторов могут быть доступны с помощью react-redux::[email protected] любым компонентом! Что делает состояние хранилища Redux доступным для всего приложения, в то время как состояние компонента является эксклюзивным для самого себя.

+34
источник

Этот пример реакции и редукса основан на примере Мохамеда Меллуки. Но проверяет, используя правила prettify и linting. Обратите внимание, что мы определяем наши методы props и dispatch, используя PropTypes, чтобы наш компилятор не кричал на нас. Этот пример также включал несколько строк кода, которые отсутствовали в примере Мохамеда. Чтобы использовать Connect, вам нужно будет импортировать его из Reaction-redux. Этот пример также связывает метод filterItems, это предотвратит проблемы области действия в компоненте. Этот исходный код был автоматически отформатирован с использованием JavaScript Prettify.

import React, { Component } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

class ItemsContainer extends Component {
  constructor(props) {
    super(props);
    const { items, filters } = props;
    this.state = {
      items,
      filteredItems: filterItems(items, filters),
    };
    this.filterItems = this.filterItems.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    const { itmes } = this.state;
    const { filters } = nextProps;
    this.setState({ filteredItems: filterItems(items, filters) });
  }

  filterItems = (items, filters) => {
    /* return filtered list */
  };

  render() {
    return <View>/*display the filtered items */</View>;
  }
}

/*
define dispatch methods in propTypes so that they are validated.
*/
ItemsContainer.propTypes = {
  items: PropTypes.array.isRequired,
  filters: PropTypes.array.isRequired,
  onMyAction: PropTypes.func.isRequired,
};

/*
map state to props
*/
const mapStateToProps = state => ({
  items: state.App.Items.List,
  filters: state.App.Items.Filters,
});

/*
connect dispatch to props so that you can call the methods from the active props scope.
The defined method 'onMyAction' can be called in the scope of the componets props.
*/
const mapDispatchToProps = dispatch => ({
  onMyAction: value => {
    dispatch(() => console.log('${value}'));
  },
});

/* clean way of setting up the connect. */
export default connect(mapStateToProps, mapDispatchToProps)(ItemsContainer);

Этот пример кода является хорошим шаблоном для отправной точки для вашего компонента.

+5
источник

React-Redux connect используется для обновления хранилища для каждого действия.

import { connect } from 'react-redux';

const AppContainer = connect(  
  mapStateToProps,
  mapDispatchToProps
)(App);

export default AppContainer;

Это очень просто и понятно объяснено в этом blog.

Вы можете клонировать проект github или скопировать код из этого блога, чтобы понять соединение Redux.

+2
источник

Вот схема/шаблон для описания поведения mapStateToProps:

(Это значительно упрощенная реализация того, что делает контейнер Redux.)

class MyComponentContainer extends Component {
  mapStateToProps(state) {
    // this function is specific to this particular container
    return state.foo.bar;
  }

  render() {
    // This is how you get the current state from Redux,
    // and would be identical, no mater what mapStateToProps does
    const { state } = this.context.store.getState();

    const props = this.mapStateToProps(state);

    return <MyComponent {...this.props} {...props} />;
  }
}

и следующий

function buildReduxContainer(ChildComponentClass, mapStateToProps) {
  return class Container extends Component {
    render() {
      const { state } = this.context.store.getState();

      const props = mapStateToProps(state);

      return <ChildComponentClass {...this.props} {...props} />;
    }
  }
}
0
источник
import React from 'react';
import {connect} from 'react-redux';
import Userlist from './Userlist';

class Userdetails extends React.Component{

render(){
    return(
        <div>
            <p>Name : <span>{this.props.user.name}</span></p>
            <p>ID : <span>{this.props.user.id}</span></p>
            <p>Working : <span>{this.props.user.Working}</span></p>
            <p>Age : <span>{this.props.user.age}</span></p>
        </div>
    );
 }

}

 function mapStateToProps(state){  
  return {
    user:state.activeUser  
}

}

  export default connect(mapStateToProps, null)(Userdetails);
-2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос