React-Redux ve mapStateToProps () yöntemini anlama


220

Tepki-redux bağlantı yöntemini ve parametre olarak aldığı işlevleri anlamaya çalışıyorum. Özellikle mapStateToProps().

Anladığım şekilde, dönüş değeri mapStateToProps, anahtarlar sahne olarak hedef bileşeninize (bileşen bağlantısı uygulanır) aktarılan durumdan (mağazada olduğu gibi) türetilmiş bir nesne olacaktır.

Bu, hedef bileşeniniz tarafından tüketilen durumun, mağazanızda depolandığından durumdan çok farklı bir yapıya sahip olabileceği anlamına gelir.

S: Bu uygun mu?
S: Bu bekleniyor mu?
S: Bu bir anti-desen mi?


11
Karışıma başka bir cevap eklemek istemiyorum ... ama kimsenin sorunuza gerçekten cevap vermediğini anlıyorum ... bence, bu bir anti-desen DEĞİL . Anahtar mapStateTo Props adındadır ve bir bileşenin tüketmesi için salt okunur özellikler iletiyorsunuzdur . Sık sık, sunum bileşenine geçmeden önce durumu almak ve değiştirmek için konteyner bileşenlerimi kullanacağım.
Matthew Brent

3
Bu şekilde sunum bileşenim çok daha basit ... mantıklı this.props.someDatadeğil aksine render yapıyor olabilir miyim this.props.someKey[someOtherKey].someData?
Matthew Brent

3
Bu öğretici yeterince iyi açıklıyor: learn.co/lessons/map-state-to-props-readme
Ayan

Merhaba Pablo, lütfen seçtiğiniz cevabı tekrar düşünün.
vsync

Nasıl yeniden düşünün?
Pablo Barría Urenda

Yanıtlar:


56

S: Is this ok?
A: evet

S: Is this expected?
Evet, bu bekleniyor (reaktif-redux kullanıyorsanız).

S: Is this an anti-pattern?
A: Hayır, bu bir anti-desen değil.

Buna bileşeninizi "bağlama" veya "akıllı yapma" denir. Tasarım gereği.

Bileşeninizi durumunuzdan kodunuzun modülerliğini artıran ek bir zamanda ayırmanızı sağlar. Ayrıca, bileşen durumunuzu, aslında Redux modeline uymanıza yardımcı olan uygulama durumunuzun bir alt kümesi olarak basitleştirmenizi sağlar.

Bunu şu şekilde düşünün: bir mağazanın başvurunuzun tüm durumunu içermesi gerekir.
Büyük uygulamalar için bu, birçok katmanın derinliklerine yerleştirilmiş düzinelerce özellik içerebilir.
Her çağrıda tüm bunları çekmek istemezsiniz (pahalı).

mapStateToPropsAnalog olmadan veya bir şekilde analog olmadan , performansınızı artırmak / basitleştirmek için durumunuzu başka bir şekilde kazma eğiliminde olursunuz.


6
Her bileşene tüm mağazaya erişim izni vermenin, ne kadar büyük olsa da, performansla ilgisi olduğunu düşünmüyorum. Nesnelerin etrafından geçilmesi her zaman aynı nesne olduğu için hafızayı kaplamaz. Bir bileşene ihtiyaç duyduğu parçaları getirmenin tek nedeni muhtemelen 2 nedendir: (1) -Daha kolay derin erişim (2) -Bir bileşenin kendisine ait olmayan durumu
dağıtabileceği

@vsync Bunun daha kolay derin erişime nasıl olanak tanıdığını açıklar mısınız? Yerel duruma başvurmak yerine artık yerel desteklerin kullanılabileceği anlamına mı geliyor, yani daha okunabilir mi?
Siddhartha

Ayrıca, bir bileşen, değişmez olarak aktarıldığında ona ait olmayan bir durumu nasıl berbat edebilir?
Siddhartha

devlet değişmezse, o zaman bu iyi, ama yine de, iyi bir uygulama olarak, sadece kendileriyle ilgili parçaları bileşenlere maruz bırakmak daha iyidir. Bu aynı zamanda diğer geliştiricilerin hangi bileşenlerin ( durum nesnesinin) o bileşenle ilgili olduğunu daha iyi anlamalarına yardımcı olur . "Daha kolay erişim" ile ilgili olarak, bazı derin durumlara giden yolun doğrudan bir pervane olarak bileşene geçmesi ve bu bileşenin perde arkasında Redux olduğu gerçeğine kör olması bir anlamda daha kolaydır. Bileşenler hangi devlet yönetim sisteminin kullanıldığına dikkat etmemeli ve yalnızca aldıkları desteklerle çalışmalıdır.
vsync

119

Evet bu doğru. Durum özelliklerine erişmenin daha kolay bir yoluna sahip olmak için sadece bir yardımcı işlevi

postsUygulamanızda bir anahtarınız olduğunu düşününstate.posts

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

Ve bileşen Posts

Varsayılan connect()(Posts)olarak bağlı Bileşen için tüm durum aksesuarlarını kullanılabilir hale getirir

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

Şimdi state.postsbileşeninizle eşleştirdiğinizde biraz daha hoş olur

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

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

mapDispatchToProps

normalde yazmak zorundasın dispatch(anActionCreator())

ile bindActionCreatorsdaha kolay gibi de yapabilir

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

Şimdi bunu Bileşeninizde kullanabilirsiniz

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

ActionCreators üzerinde güncelleme ..

Bir actionCreator örneği: deletePost

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

Yani, bindActionCreatorssadece eylemlerinizi alacak, onları dispatchçağrıya sarın . (Redux'un kaynak kodunu okumadım, ancak uygulama şöyle görünebilir:

const bindActionCreators = (actions, dispatch) => {
  return Object.keys(actions).reduce(actionsMap, actionNameInProps => {
    actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))
    return actionsMap;
  }, {})
}

Ben bir şey kaçırabilirsiniz düşünüyorum, ama nerede yok dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)olur fetchPostsve deletePostgelen eylemleri geçti?
ilyo

@ilyo Bunlar sizin eylem yaratıcılarınız, onları içe aktarmak zorundasınız
webdeb

2
Güzel cevap! Bu kod parçasının state => state.posts( mapStateToPropsişlev) React'e güncellendiğinde bileşenin yeniden oluşturulmasını tetikleyeceği durumları söyleyeceğini vurgulamak güzel olduğunu düşünüyorum .
Miguel Péres

38

İlk kısmı doğru yaptınız:

Evet mapStateToProps, depo durumunu bir argüman / param (tarafından sağlanan react-redux::connect) olarak içerir ve bileşeni mağaza durumunun belirli bir bölümüne bağlamak için kullanılır.

Bağlayarak, geri dönen nesnenin mapStateToPropsyapım aşamasında sahne olarak sağlanacağı ve daha sonra yapılacak herhangi bir değişikliğin sağlanacağı anlamına gelir componentWillReceiveProps.

Observer tasarım desenini biliyorsanız, tam olarak bu veya küçük bir varyasyonu vardır.

Bir örnek, işleri daha net hale getirmeye yardımcı olacaktır:

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

itemsFiltersEkranı işleyen ve filtre durumunu Redux Store durumuna devam eden denilen başka bir tepki bileşeni olabilir , Demo bileşeni Redux Store durum filtrelerini "dinliyor" veya "abone oluyor", böylece filtreler mağaza durumu değiştiğinde (yardımıyla filtersComponent) tepki veriyor -redux, bir değişiklik olduğunu algılar ve componentWillReceivePropsbu örnekte öğelerin bir yeniden filtresini tetikleyecek ve tepki durumunun değişmesi nedeniyle ekranı yenileyecek olan değişiklikleri göndererek tüm dinleme / abone olunan bileşenleri bildirir veya "yayınlar" .

Örneğin kafa karıştırıcı olup olmadığını veya daha iyi bir açıklama sağlayacak kadar net olup olmadığını bana bildirin.

Gelince: Bu, hedef bileşeniniz tarafından tüketilen durumun, mağazanızda depolandığı haliyle durumdan çok farklı bir yapıya sahip olabileceği anlamına gelir.

Soruyu alamadım, ancak reaksiyon durumunun ( this.setState) Redux Mağazası durumundan tamamen farklı olduğunu bilin !

Reaksiyon durumu, reaksiyon bileşeninin yeniden çizilmesini ve davranışını işlemek için kullanılır. Reaksiyon durumu sadece bileşene dahil edilir.

Redux Mağazası durumu, Redux redüktör durumlarının bir kombinasyonudur, her biri küçük bir kısım uygulama mantığını yönetmekten sorumludur. Bu redüktör özelliklerine react-redux::connect@mapStateToPropsherhangi bir bileşen yardımıyla erişilebilir ! Bileşen durumu kendisine özelken Redux mağaza durumunu erişilebilir uygulamayı genişletin.


5

Bu tepki ve redux örneği Mohamed Mellouki'nin örneğini temel alıyor. Ancak, güzelleştirme ve linting kurallarını kullanarak doğrular . PropTypes kullanarak sahne ve dağıtım yöntemlerimizi tanımladığımızı ve derleyicimizin bize çığlık atmayacağını unutmayın . Bu örnek, Mohamed örneğinde eksik olan bazı kod satırlarını da içeriyordu. Bağlanmayı kullanmak için onu tepki-redux'dan içe aktarmanız gerekir . Bu örnek ayrıca filterItems yöntemini bağlar , bu bileşendeki kapsam sorunlarını önler . Bu kaynak kodu JavaScript Prettify kullanılarak otomatik olarak biçimlendirilmiştir .

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

Bu örnek kod, bileşeniniz için bir başlangıç ​​yeri için iyi bir şablondur.


2

React-Redux connect , her eylem için mağazayı güncellemek amacıyla kullanılır.

import { connect } from 'react-redux';

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

export default AppContainer;

Bu blogda çok basit ve açık bir şekilde açıklanmıştır .

Redux bağlantısını anlamak için github projesini klonlayabilir veya kodu o blogdan kopyalayıp yapıştırabilirsiniz.


iyi manuel formapStateToProps thegreatcodeadventure.com/…
zloctb

1

İşte davranışını tanımlamak için bir anahat / kazan plakası mapStateToProps:

(Bu, bir Redux konteynerinin yaptıklarının büyük ölçüde basitleştirilmiş bir uygulamasıdır.)

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

ve sonra

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

-2
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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.