Memahami React-Redux dan mapStateToProps ()

219

Saya mencoba memahami metode koneksi dari reaksi-redux, dan fungsi yang dibutuhkan sebagai parameter. Khususnya mapStateToProps().

Cara saya memahaminya, nilai pengembalian mapStateToPropsakan menjadi objek yang berasal dari negara (seperti yang tinggal di toko), yang kunci-kuncinya akan diteruskan ke komponen target Anda (menghubungkan komponen diterapkan ke) sebagai alat peraga.

Ini berarti bahwa keadaan yang dikonsumsi oleh komponen target Anda dapat memiliki struktur yang sangat berbeda dari keadaan saat disimpan di toko Anda.

T: Apakah ini OK?
T: Apakah ini diharapkan?
T: Apakah ini anti-pola?

Pablo Barría Urenda
sumber
11
Saya tidak ingin menambahkan jawaban lain ke campuran ... tapi saya sadar tidak ada yang benar-benar menjawab pertanyaan Anda ... menurut saya, BUKAN anti-pola. Kuncinya ada di nama mapStateTo Props yang Anda lewatkan properti hanya-baca untuk dikonsumsi komponen. Saya akan sering menggunakan komponen kontainer saya untuk mengambil status dan mengubahnya sebelum meneruskannya ke komponen presentasi.
Matius Brent
3
Dengan cara ini komponen presentasi saya jauh lebih sederhana ... Saya mungkin merender this.props.someDatasebagai lawan dari this.props.someKey[someOtherKey].someData... masuk akal?
Matthew Brent
3
Tutorial ini menjelaskannya dengan cukup baik: learn.co/lessons/map-state-to-props-readme
Ayan
Hai Pablo, harap pertimbangkan kembali jawaban pilihan Anda.
vsync
Pertimbangkan kembali bagaimana?
Pablo Barría Urenda

Jawaban:

56

T: Is this ok?
A: ya

T: Is this expected?
Ya, ini diharapkan (jika Anda menggunakan react-redux).

T: Is this an anti-pattern?
A: Tidak, ini bukan anti-pola.

Ini disebut "menghubungkan" komponen Anda atau "membuatnya pintar". Ini dengan desain.

Ini memungkinkan Anda memisahkan komponen dari keadaan Anda waktu tambahan yang meningkatkan modularitas kode Anda. Ini juga memungkinkan Anda untuk menyederhanakan keadaan komponen Anda sebagai bagian dari keadaan aplikasi Anda yang, pada kenyataannya, membantu Anda mematuhi pola Redux.

Pikirkan seperti ini: toko seharusnya berisi seluruh keadaan aplikasi Anda.
Untuk aplikasi besar, ini bisa berisi lusinan properti bersarang banyak lapisan dalam.
Anda tidak ingin mengangkut semua yang ada di setiap panggilan (mahal).

Tanpa mapStateToPropsatau beberapa analognya, Anda akan tergoda untuk mengukir keadaan Anda dengan cara lain untuk meningkatkan kinerja / menyederhanakan.

Richard Strickland
sumber
6
Saya tidak berpikir bahwa memberikan setiap dan setiap komponen akses ke seluruh toko, betapapun besarnya, ada hubungannya dengan kinerja. melewati objek di sekitar tidak memakan memori karena selalu objek yang sama . Satu-satunya alasan membawa ke komponen bagian yang dibutuhkan mungkin adalah 2 alasan: (1) -Akses yang lebih mudah (2) -Hindari bug di mana komponen dapat mengacaukan keadaan yang bukan miliknya
vsync
@vsync Bisakah Anda jelaskan bagaimana hal itu memungkinkan akses yang lebih mudah dan dalam? Apakah maksud Anda bahwa alat peraga lokal sekarang dapat digunakan alih-alih harus merujuk pada negara global sehingga lebih mudah dibaca?
Siddhartha
Juga, bagaimana mungkin komponen mengacaukan status yang bukan miliknya ketika status itu dilewatkan sebagai tidak berubah?
Siddhartha
jika keadaan tidak berubah maka saya kira itu baik-baik saja, tapi tetap saja, sebagai praktik yang baik, lebih baik membuka komponen hanya bagian yang relevan dengan mereka. Ini juga membantu pengembang lain lebih memahami bagian mana ( objek negara ) yang relevan dengan komponen itu. Mengenai "akses yang lebih mudah", lebih mudah dalam arti bahwa jalan menuju keadaan yang dalam secara langsung diteruskan ke komponen sebagai penyangga, dan komponen itu buta terhadap kenyataan ada Redux di belakang layar. Komponen tidak boleh peduli sistem manajemen negara mana yang digunakan, dan mereka harus bekerja hanya dengan alat peraga yang mereka terima.
vsync
119

Ya itu benar. Ini hanya fungsi pembantu untuk memiliki cara yang lebih sederhana untuk mengakses properti negara Anda

Bayangkan Anda memiliki postskunci di Aplikasi Andastate.posts

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

Dan komponen Posts

Secara default connect()(Posts)akan membuat semua alat peraga keadaan tersedia untuk Komponen yang terhubung

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

Sekarang ketika Anda memetakan state.postske komponen Anda itu menjadi sedikit lebih baik

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

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

mapDispatchToProps

biasanya kamu harus menulis dispatch(anActionCreator())

dengan bindActionCreatorsAnda bisa melakukannya juga lebih mudah suka

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

Sekarang Anda dapat menggunakannya di Komponen Anda

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

Perbarui pada actionCreators ..

Contoh dari actionCreator: deletePost

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

Jadi, bindActionCreatorshanya akan mengambil tindakan Anda, bungkus menjadi dispatchpanggilan. (Saya tidak membaca kode sumber redux, tetapi implementasinya mungkin terlihat seperti ini:

const bindActionCreators = (actions, dispatch) => {
  return Object.keys(actions).reduce(actionsMap, actionNameInProps => {
    actionsMap[actionNameInProps] = (...args) => dispatch(actions[actionNameInProps].call(null, ...args))
    return actionsMap;
  }, {})
}
webdeb
sumber
Saya pikir saya mungkin melewatkan sesuatu, tetapi dari mana dispatch => bindActionCreators({fetchPosts, deletePost}, dispatch)mendapatkan fetchPostsdan deletePosttindakan dilewatkan?
ilyo
@ilyo ini adalah pembuat aksi Anda, Anda harus mengimpornya
webdeb
2
Jawaban bagus! Saya pikir itu juga baik untuk menekankan bahwa potongan kode ini state => state.posts( mapStateToPropsfungsi) akan memberitahu Bereaksi keadaan apa yang akan memicu re-render komponen ketika diperbarui.
Miguel Péres
38

Anda mendapatkan bagian pertama yang benar:

Ya mapStateToPropsmemiliki status Store sebagai argumen / param (disediakan oleh react-redux::connect) dan digunakan untuk menghubungkan komponen dengan bagian tertentu dari state store.

Dengan menghubungkan maksud saya objek yang dikembalikan oleh mapStateToPropsakan diberikan pada waktu konstruksi sebagai alat peraga dan setiap perubahan berikutnya akan tersedia melalui componentWillReceiveProps.

Jika Anda tahu pola desain Observer, itu persis variasi kecil itu.

Contoh akan membantu memperjelas:

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

Mungkin ada komponen reaksi lain yang disebut itemsFiltersyang menangani tampilan dan mempertahankan status filter ke status Redux Store, komponen Demo adalah "mendengarkan" atau "berlangganan" ke filter status Redux Store sehingga setiap kali filter menyatakan perubahan kondisi toko (dengan bantuan filtersComponent) bereaksi -redux mendeteksi bahwa ada perubahan dan memberitahukan atau "mempublikasikan" semua komponen yang mendengarkan / berlangganan dengan mengirimkan perubahan yang mereka componentWillReceivePropsdalam contoh ini akan memicu penyaringan item dan menyegarkan tampilan karena fakta bahwa keadaan reaksi telah berubah .

Beri tahu saya jika contohnya membingungkan atau tidak cukup jelas untuk memberikan penjelasan yang lebih baik.

Adapun: Ini berarti bahwa keadaan yang dikonsumsi oleh komponen target Anda dapat memiliki struktur yang sangat berbeda dari keadaan seperti yang disimpan di toko Anda.

Saya tidak mendapatkan pertanyaan, tetapi hanya tahu bahwa keadaan reaksi ( this.setState) sama sekali berbeda dari keadaan Toko Redux!

Keadaan reaksi digunakan untuk menangani redraw dan perilaku komponen reaksi. Keadaan bereaksi terkandung ke komponen secara eksklusif.

Keadaan Redux Store adalah kombinasi dari kondisi reduksi Redux, masing-masing bertanggung jawab mengelola sebagian kecil logika aplikasi. Atribut reduksi tersebut dapat diakses dengan bantuan react-redux::connect@mapStateToPropskomponen apa pun! Yang membuat aplikasi negara toko Redux dapat diakses secara luas sementara status komponen eksklusif untuk dirinya sendiri.

Mohamed Mellouki
sumber
5

Ini bereaksi & redux contoh didasarkan dari contoh Mohamed Mellouki ini. Tetapi memvalidasi menggunakan aturan prettify dan linting . Perhatikan bahwa kami mendefinisikan alat peraga dan metode pengiriman kami menggunakan PropTypes sehingga kompiler kami tidak meneriaki kami. Contoh ini juga termasuk beberapa baris kode yang telah hilang dalam contoh Mohamed. Untuk menggunakan koneksi, Anda harus mengimpornya dari react-redux . Contoh ini juga mengikat metode filterItems ini akan mencegah masalah lingkup dalam komponen . Kode sumber ini telah diformat secara otomatis menggunakan 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);

Kode contoh ini adalah templat yang baik untuk tempat awal untuk komponen Anda.

Patrick W. McMahon
sumber
2

React-Redux connect digunakan untuk memperbarui toko untuk setiap tindakan.

import { connect } from 'react-redux';

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

export default AppContainer;

Ini sangat sederhana dan jelas dijelaskan di blog ini .

Anda dapat mengkloning proyek github atau menyalin kode dari blog tersebut untuk memahami koneksi Redux.

ArunValaven
sumber
manual formapstateToProps thegreatcodeadventure.com/…
zloctb
1

Berikut ini outline / boilerplate untuk menjelaskan perilaku mapStateToProps:

(Ini adalah implementasi yang sangat disederhanakan dari apa yang dilakukan wadah 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} />;
  }
}

dan selanjutnya

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} />;
    }
  }
}
zloctb
sumber
-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);
SM Chinna
sumber