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

Я пытаюсь понять метод connect redux/" class="blnk">react-redux и функции, которые он принимает в качестве параметров. В частности mapStateToProps().

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

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

Q: это нормально?
Вопрос: это нормально?
В.: это анти-паттерн?

6 ответов


Q:Is this ok?
A: да

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

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

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

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

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

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


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

представьте, что у вас есть 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 к вашему компоненту он получает немного лучше!--18-->

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;
  }, {})
}

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

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

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

если вы знаете шаблон дизайна наблюдателя, это именно то или небольшое изменение он.

пример поможет сделать вещи более ясными:

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

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

        this.state = {
            items: props.items, //provided by connect@mapStateToProps
            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's another subject
)(ItemsContainer);

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

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

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

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

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

состояние Redux Store-это комбинация состояний Redux reducers, каждый из которых отвечает за управление небольшой частью логики приложения. Эти атрибуты редукторов можно получить с помощью react-redux::connect@mapStateToProps любой компонент! Которые делают состояние магазина Redux доступным для приложения, а состояние компонента является эксклюзивным для самого себя.


этой реагировать & redux пример основан на примере Мохамеда Меллуки. Но проверяет использование prettify и правила пылеобразования. Обратите внимание, что мы определяем наши реквизиты и отправка методы с использованием PropTypes чтобы наш компилятор не кричал на нас. Этот пример также включал некоторые строки кода, которые отсутствовали в Mohamed's образец. Для использования подключения вам нужно будет импортировать его из react-redux. Этот пример также персонализация метод filterItems это предотвратит область проблемы в the компонент. Этот исходный код был автоматически отформатирован с помощью 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);

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


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

import { connect } from 'react-redux';

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

export default AppContainer;

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

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


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){  *state is your redux-store object* 
  return {
    user:state.activeUser  
}

}

  export default connect(mapStateToProps)(Userdetails);