'dispatch' ไม่ใช่ฟังก์ชันเมื่ออาร์กิวเมนต์ไปยัง mapToDispatchToProps () ใน Redux


124

ฉันเป็นมือใหม่ javascript / redux / react ที่สร้างแอปพลิเคชั่นขนาดเล็กที่มี redux, react-redux และ react ด้วยเหตุผลบางประการเมื่อใช้ฟังก์ชัน mapDispatchToProps ควบคู่กับการเชื่อมต่อ (การเชื่อมต่อแบบ react-redux) ฉันได้รับ TypeError ซึ่งระบุว่าการจัดส่งไม่ใช่ฟังก์ชันเมื่อฉันพยายามเรียกใช้ prop ที่เป็นผลลัพธ์ อย่างไรก็ตามเมื่อฉันเรียกการจัดส่งเป็นเสา (ดูฟังก์ชัน setAddr ในรหัสที่ให้มา) มันใช้งานได้

ฉันสงสัยว่าทำไมจึงเป็นเช่นนี้ในตัวอย่างแอป TODO ในเอกสาร redux เมธอด mapDispatchToProps ได้รับการตั้งค่าในลักษณะเดียวกัน เมื่อฉัน console.log (จัดส่ง) ภายในฟังก์ชันมันจะบอกว่าการจัดส่งเป็นวัตถุประเภท ฉันสามารถใช้การจัดส่งด้วยวิธีนี้ต่อไปได้ แต่ฉันจะรู้สึกดีขึ้นเมื่อทราบว่าเหตุใดจึงเกิดขึ้นก่อนที่จะดำเนินการต่อด้วย redux ฉันใช้ webpack กับ babel-loaders เพื่อรวบรวม

รหัสของฉัน:

import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import { setAddresses } from '../actions.js';
import GeoCode from './geoCode.js';
import FlatButton from 'material-ui/lib/flat-button';

const Start = React.createClass({
    propTypes: {
        onSubmit: PropTypes.func.isRequired
    },

    setAddr: function(){
        this.props.dispatch(
            setAddresses({
                pickup: this.refs.pickup.state.address,
                dropoff: this.refs.dropoff.state.address
            })
        )   

    },

    render: function() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-6">
                        <GeoCode ref='pickup' />
                    </div>
                    <div className="col-xs-6">
                        <GeoCode ref='dropoff' />
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Does Not Work'
                            onClick={this.props.onSubmit({
                                pickup: this.refs.pickup.state.address,
                                dropoff: this.refs.dropoff.state.address
                            })} 
                            />
                    </div>
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Works'
                            onClick={this.setAddr} 
                            />
                    </div>
                </div>
            </div>
        );
    }
})

const mapDispatchToProps = (dispatch) => {
    return {
        onSubmit: (data) => {
            dispatch(setAddresses(data))
        }
    }
}

const StartContainer = connect(mapDispatchToProps)(Start)

export default StartContainer

ไชโย


ฉันมีปัญหานี้และสิ่งนี้ช่วยฉันแก้ได้
Alex W

คำตอบ:


249

หากคุณต้องการใช้mapDispatchToPropsโดยไม่ต้องmapStateToPropsใช้nullสำหรับอาร์กิวเมนต์แรก

export default connect(null, mapDispatchToProps)(Start)


4
นี่คือสิ่งที่ฉันมองหา ตอนนี้ฉันรู้แล้วว่าฉันแค่ต้องการส่งการกระทำบางอย่างออกไป
Emperor Krauser

นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณสำหรับโซลูชันที่สมบูรณ์แบบ จะเกิดอะไรขึ้นถ้าเราไม่ต้องใช้ mapDispatchToProps ในส่วนประกอบใด ๆ ของเรา? เป็นวิธีเดียวกับที่เราต้องจัดการกับสถานการณ์นั้นหรือไม่?
อรุณราม

1
หากคุณไม่ต้องการmapDispatchToPropsก็อย่าเพิ่มอาร์กิวเมนต์นั้นในconnect:connect(mapStateToProps)(MyComponent)
inostia

107

คุณเพิ่งขาดอาร์กิวเมนต์แรกconnectซึ่งเป็นmapStateToPropsวิธีการ ข้อความที่ตัดตอนมาจากแอป Redux todo:

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

3
จำเป็นต้องใช้วิธีนี้หรือไม่? วิธีนี้เพียงแค่จับระบุว่าถ้าเราไม่ต้องการวิธีนี้?
Muneem Habib

6
@MuneemHabib ดูคำตอบของ inostia สำหรับวิธีไม่จัดหาวิธีนี้หากคุณไม่ต้องการ
Brandon


6

ฉันแก้ไขได้โดยแลกเปลี่ยนข้อโต้แย้งฉันใช้

export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)

ซึ่งผิด mapStateToPropsจะต้องมีอาร์กิวเมนต์แรก:

export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)

ตอนนี้ฟังดูชัดเจน แต่อาจช่วยใครบางคนได้


3

ฉันต้องการตัวอย่างโดยใช้React.Componentดังนั้นฉันจึงโพสต์:

import React from 'react';
import * as Redux from 'react-redux';

class NavigationHeader extends React.Component {

}

const mapStateToProps = function (store) {
    console.log(`mapStateToProps ${store}`);
    return {
        navigation: store.navigation
    };
};

export default Redux.connect(mapStateToProps)(NavigationHeader);

3

ปัญหา

ต่อไปนี้เป็นสิ่งที่ควรสังเกตเพื่อทำความเข้าใจพฤติกรรมของส่วนประกอบที่เชื่อมต่อในโค้ดของคุณ:

ความconnectสำคัญของเรื่อง:connect(mapStateToProps, mapDispatchToProps)

ตอบสนอง-Redux เรียกconnectด้วยอาร์กิวเมนต์แรกและอาร์กิวเมนต์ที่สองmapStateToPropsmapDispatchToProps

ดังนั้นแม้ว่าคุณจะผ่านไปแล้วmapDispatchToPropsแต่ในความเป็นจริง React-Redux ก็ถือว่าเป็นmapStateเพราะเป็นข้อโต้แย้งแรก คุณยังคงได้รับonSubmitฟังก์ชั่นการฉีดในส่วนประกอบของคุณเนื่องจากการส่งคืนmapStateจะรวมเข้ากับอุปกรณ์ประกอบฉากของคุณ แต่นั่นไม่ใช่วิธีที่mapDispatchควรฉีด

คุณอาจจะใช้โดยไม่ต้องกำหนดmapDispatch mapStateผ่านในnullในสถานที่mapStateและองค์ประกอบของคุณจะไม่อยู่ภายใต้การเปลี่ยนแปลงการจัดเก็บ

ส่วนประกอบที่เชื่อมต่อได้รับdispatchตามค่าเริ่มต้นเมื่อไม่มีmapDispatchให้

นอกจากนี้ยังมีส่วนประกอบของคุณได้รับdispatchเพราะมันได้รับสำหรับตำแหน่งที่สองสำหรับnull mapDispatchหากคุณต้องผ่านในส่วนประกอบของคุณจะไม่ได้รับmapDispatchdispatch

แนวทางปฏิบัติทั่วไป

คำตอบข้างต้นว่าเหตุใดส่วนประกอบจึงทำงานในลักษณะนั้น แม้ว่าจะเป็นเรื่องธรรมดาที่คุณจะส่งผ่านผู้สร้างการกระทำของคุณโดยใช้mapStateToPropsชวเลขวัตถุ และเรียกสิ่งนั้นภายในส่วนประกอบของคุณonSubmitนั่นคือ:

import { setAddresses } from '../actions.js'

const Start = (props) => {
  // ... omitted
  return <div>
    {/** omitted */}
    <FlatButton 
       label='Does Not Work'
       onClick={this.props.setAddresses({
         pickup: this.refs.pickup.state.address,
         dropoff: this.refs.dropoff.state.address
       })} 
    />
  </div>
};

const mapStateToProps = { setAddresses };
export default connect(null, mapDispatchToProps)(Start)

0

เมื่อคุณไม่ได้ระบุmapDispatchToPropsเป็นอาร์กิวเมนต์ที่สองเช่นนี้:

export default connect(mapStateToProps)(Checkbox)

จากนั้นคุณจะได้รับการจัดส่งไปยังอุปกรณ์ประกอบฉากโดยอัตโนมัติดังนั้นคุณสามารถ:

class SomeComp extends React.Component {
  constructor(props, context) {
    super(props, context);
  }
  componentDidMount() {
    this.props.dispatch(ACTION GOES HERE);
  }
....

ไม่มี mapDispatchToProps ใด ๆ


0

ฉันใช้แบบนี้ .. อาร์กิวเมนต์แรกที่เข้าใจง่ายคือ mapStateToProps และอาร์กิวเมนต์ที่สองคือ mapDispatchToProps ในท้ายที่สุดเชื่อมต่อกับฟังก์ชัน / คลาส

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

ถ้าคุณไม่มีอาร์กิวเมนต์แรกให้ส่งค่า null / undefined แล้วอาร์กิวเมนต์ที่สอง ..
อับดุลโมอิซ

0

บางครั้งข้อผิดพลาดนี้ยังเกิดขึ้นเมื่อคุณเปลี่ยนลำดับของฟังก์ชันคอมโพเนนต์ในขณะที่ส่งต่อเพื่อเชื่อมต่อ

คำสั่งซื้อไม่ถูกต้อง:

export default connect(mapDispatchToProps, mapStateToProps)(TodoList);

ลำดับที่ถูกต้อง:

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

0

ข้อผิดพลาดที่บางคนอาจก้าวเข้าไปในคำถามนี้ แต่ไม่ได้ระบุไว้ในคำตอบเนื่องจากมีความแตกต่างกันเล็กน้อยในโครงสร้างโค้ด แต่ส่งกลับข้อผิดพลาดเดียวกันทุกประการ

ข้อผิดพลาดนี้เกิดขึ้นเมื่อใช้bindActionCreatorsและไม่ผ่านdispatchฟังก์ชัน

รหัสข้อผิดพลาด

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    });
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

รหัสคงที่

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    }, dispatch);
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

ฟังก์ชันdispatchขาดหายไปในรหัสข้อผิดพลาด


0

ฟังก์ชัน React-redux 'connect' ยอมรับสองอาร์กิวเมนต์แรกคือ mapStateToProps และที่สองคือ mapDispatchToProps ตรวจสอบด้านล่างเช่น

export default connect(mapStateToProps, mapDispatchToProps)(Index); `

หากเราไม่ต้องการดึงสถานะจาก redux เราก็ตั้งค่า null แทน mapStateToProps

export default connect(null, mapDispatchToProps)(Index);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.