使用通过 react、redux 和 react-redux 完成的组件以及在 react 应用程序中使用 webpack 构建时出错

Posted

技术标签:

【中文标题】使用通过 react、redux 和 react-redux 完成的组件以及在 react 应用程序中使用 webpack 构建时出错【英文标题】:Error using component done with react,redux and react-redux and build with webpack in react application 【发布时间】:2016-08-31 06:05:13 【问题描述】:

我已经使用 react、redux 和 react-redux 完成了一个包含 store 的组件。 使用 webpack 打包代码。(请检查下面附加的代码)

当我想在另一个 react 项目中使用 webpack 构建组件时,我遇到了以下问题。

警告:React.createElement:类型不应为 null、未定义、 布尔值或数字。它应该是一个字符串(对于 DOM 元素)或 ReactClass(用于复合组件)。

未捕获的不变违规:元素类型无效:预期为 字符串(用于内置组件)或类/函数(用于复合 组件)但得到:未定义。

然后我继续在代码中进行以下修改,之前我对 connectbindActionCreators 进行了如下解构分配

import connect from 'react-redux';
import  bindActionCreators from 'redux';
import  actions from '../app/redux/actions';

然后我改变了它,如下所示,删除 connect 和 bindActionCreators 周围的花括号

import React from 'react';

import connect from 'react-redux';
import  bindActionCreators from 'redux';
import  actions from '../app/redux/actions';

import postal from 'postal';

const channel = postal.channel("msplayer");

class Player extends React.Component 

但在那之后我面临以下错误,因为我猜这与 babel 将 ES6 转换为 ES5 有关,但不确定要遵循哪些步骤来解决此问题,希望得到答案或一些指针解决这个问题?

Uncaught TypeError: (0 , _reactRedux2.default) 不是函数

未捕获的类型错误:无法读取未定义的属性“PlayerWrapper”

组件代码

import React from 'react';

import connect from 'react-redux';
import  bindActionCreators from 'redux';
import  actions from '../app/redux/actions';

import postal from 'postal';

const channel = postal.channel("msplayer");

class Player extends React.Component 


    constructor() 
        super();
        this.state = 
            userData: ,
            uiStates: 
                panelClosed: true,
                submissionSelected: false
            ,
            selectedSubmission: 
        ;
        this.subSelectChannel = null;
        this.tabSelectChannel = null;
    


    componentWillMount() 
        require('!style!css!../app/styles/player.css');
    

    componentDidMount() 
        var _that = this;
        var _msData = 
            piToken: this.props.piToken,
            sectionId: this.props.sectionId,
            assignmentId: this.props.assignmentId,
            userId: this.props.userId
        ;

        this.props.actions.getAssignmentData(msData);
        this.props.actions.getPeerSubmissionData(msData);

        this.subSelectChannel = channel.subscribe("submission.selected", function (data, envelope) 
            _that.setState(
                    uiStates: Object.assign(, _that.state.uiStates, 
                        "submissionSelected": true
                    )
                
            );
            _that.setState(
                    selectedSubmission: data.submission
                
            );
        );

        this.tabSelectChannel = channel.subscribe("tab.selected", function (data, envelope) 
            if (data.submitted) 
                _that.showSubmissionDetailPanel(data.data);
             else 
                _that.hideSubmissionDetailPanel()
            
        );
    

    closePanel() 

        postal.publish(
            channel: "notifier",
            topic: "notifier.notify",
            data: 
                type: "warning",
                message: "warning message"
            
        );


        if (this.state.uiStates.panelClosed) 

            this.setState(
                    uiStates: Object.assign(, this.state.uiStates, 
                        "panelClosed": false
                    )
                
            );
         else 


            postal.publish(
                channel: "msplayer",
                topic: "close.selected",
                data: 
            );

            this.setState(
                    uiStates: Object.assign(, this.state.uiStates, 
                        "panelClosed": true,
                        "submissionSelected": false
                    )
                
            );
        
    


    hideSubmissionDetailPanel() 
        console.log("inside hide submission panel");
        this.setState(
                uiStates: Object.assign(, this.state.uiStates, 
                    "submissionSelected": false
                )
            
        );
    ;

    showSubmissionDetailPanel(data) 
        console.log("inside show submission panel");
        this.setState(
                uiStates: Object.assign(, this.state.uiStates, 
                    "submissionSelected": true
                )
            
        );

        this.setState(
            selectedSubmission: data
        );
    ;


    loadUserAssignmentData(submission) 

        this.setState(
                uiStates: Object.assign(, this.state.uiStates, 
                    "submissionSelected": true
                )
            
        );

        postal.publish(
            channel: "msplayer",
            topic: "submission.selected",
            data: 
                submission: submission
            
        );

    

    componentWillUnmount() 
        postal.unsubscribe(this.subSelectChannel);
        postal.unsubscribe(this.tabSelectChannel);
    

    render() 

        var _that = this;
        var _submittedKey = 0;
        var _unsubmittedKey = 0;
        return (
            <div className="player-container col-sm-12">
                <div className="row">
                </div>
                <div className="row">
                    <div className=_that.state.uiStates.panelClosed?"col-sm-12":"col-sm-8">
                        <div className="top-actions-panel">
                            <div className="pull-right">

                            </div>


                        </div>
                        <div className="common-view">
                            <div className="breadcrumb-panel">
                                <ol className="breadcrumb arrow-left">
                                    <li><a href="#">Communication 220</a></li>
                                    <li className="active">TED Topics for an Informative Speech</li>
                                </ol>
                            </div>
                            <div className="description-panel">
                                <p className="title">
                                    <b>Title</b>:
                                    <span>_that.props.assignment.title</span>
                                </p>
                                <p className="dueDates font-light">
                                    <b>Due </b>:<span>_that.props.assignment.startDate</span>
                                    <b> - </b><span>_that.props.assignment.endDate</span>
                                </p>
                                <p>
                                    <b>Learning Objective: </b>
                                    <span>_that.props.assignment.learningObjective</span>
                                </p>
                                <p>
                                    <b>Description: </b>
                                    <span>
                                       _that.props.assignment.description
                                    </span>
                                </p>
                            </div>

                            <div
                                className=_that.state.uiStates.submissionSelected?"row submission-info col-sm-12":"hidden">
                                <div>
                                    <span className="student-avatar">
                                        <img
                                            src=(_that.state.selectedSubmission && _that.state.selectedSubmission.userDetails && _that.state.selectedSubmission.userDetails.avatar && _that.state.selectedSubmission.userDetails.avatar!=="")?_that.state.selectedSubmission.userDetails.avatar:"../app/images/avatar.svg"/>
                                    </span>

                                    <p>
                                        <b> <span
                                            className="font-light mediaTile"><strong>(_that.state.selectedSubmission.title && _that.state.selectedSubmission.title !== null && _that.state.selectedSubmission.title !== "" ) ? _that.state.selectedSubmission.title : "."</strong></span>
                                        </b>
                                    </p>
                                    <br/>
                                    <p>
                                        <span
                                            className="font-light ">(_that.state.selectedSubmission.description && _that.state.selectedSubmission.description !== null && _that.state.selectedSubmission.description !== "") ? _that.state.selectedSubmission.description : "."</span>
                                    </p>
                                </div>
                            </div>

                            <div className="common-functionality-panel col-sm-12">
                            </div>
                        </div>
                    </div>
                    <div
                        className=_that.state.uiStates.panelClosed?"hidden":"col-sm-4 no-padding peer-review-panel">

                        <div className="review-section">
                            <button className="btn btn-link pull-left close-panel"
                                    onClick=_that.closePanel.bind(_that)>
                                <span className="reader-only">Close Student Submission Panel</span>
                                <i className="fa fa-times"></i>
                            </button>

                            <div className="submission-tabs">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    



function mapStateToProps(state) 
    return state


function mapDispatchToProps(dispatch) 
    return 
        actions: bindActionCreators(actions, dispatch)
    


export default connect(mapStateToProps, mapDispatchToProps)(Player)

组件包装代码

import React from 'react';
import Player from './app';

import bb from './redux/store'
import Provider from 'react-redux';

class PlayerWrapper extends React.Component 


    constructor(props) 
        super(props);
    

    render() 
        return (
            <Provider store=bb.store><Player piToken=this.props.piToken sectionId=this.props.sectionId
                                               assignmentId=this.props.assignmentId
                                               userId=this.props.userId/></Provider>
        )
    


export default PlayerWrapper;

webpack 构建文件

var webpack = require('webpack');

module.exports = 
    devtool: 'inline-source-map',
    entry: [
        'webpack-hot-middleware/client',
        './app/PlayerWrapper.js'
    ],
    output: 
        path: require("path").resolve("./dist/app"),
        filename: 'index.js',
        publicPath: '/'
    ,
    plugins: [
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ],
    module: 
        loaders: [
            test: /\.js?$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            query: 
                presets: ['react', 'es2015']
            
        ,
         test: /\.css$/, loader: ["css-loader","style-loader"] ,
         test: /\.scss$/, loader: "sass-loader" ,
         test: /\.(ttf|eot|svg|eot|woff|otf|png|gif)(\?v)*/, loader: "file-loader?name=fonts/[name].[ext]" 
        ]
    
;

【问题讨论】:

那么这里的问题是什么?您应该使用花括号,因为 connectbindActionCreators 被命名为导入。 我发布了我所做的,认为它会解决问题,但后来发现你提到的。现在我使用花括号,然后我得到第一个错误。想知道如何解决这个问题,为什么我在第一条错误消息中收到问题? 请发布最终代码。 我也收到此错误(_reactRedux2.default ) 【参考方案1】:

该错误意味着您尝试在某处渲染不是实际组件(或字符串)的东西

如前所述,您需要解构 connect 和 bindActionCreators,因为它们不是各自包的默认导出。

至于您的错误,同样可能的是,当您尝试渲染道具时,没有可以渲染的内容(例如它的 null 或未定义),但是由于您没有在调用 ReactDOM.render 的位置发布代码,所以我可以不确定。

【讨论】:

【参考方案2】:

我刚刚花了一些时间调试这里描述的第二个错误,并在此过程中了解了一些关于 ES6 导入语法的知识。

行:

从“react-redux”导入连接;

将从 react-redux 库中导入 default 导出。这是错误的来源:

Uncaught TypeError: (0 , _reactRedux2.default) 不是函数

改成:

import connect from 'react-redux';

将从 react-redux 库 named connect 中导入对象,这在特定情况下是您想要的。 注意花括号

查看 MDN 文档here

我也遇到了和第一个类似的错误:

警告:React.createElement:类型不应为 null、未定义、布尔值或数字。它应该是一个字符串(对于 DOM 元素)或一个 ReactClass(对于复合组件)。

当我没有像上面那样正确导入我定义的组件时。

【讨论】:

就像一个魅力。谢谢。 import Class ... 不等于 import Class... - 太棒了!如果没有人告诉我,我不知道也不会弄明白!【参考方案3】:

该错误表明在您对 reactDOM.render 的调用(您从未显示)中,您只传递了一个函数或类名,而不是组件实例。

例如,下面的例子是错误的:

ReactDOM.render(MyComponent, document.getElementById('MyComponent'));

解决方法是把第一个参数用尖括号括起来,变成一个组件实例:

ReactDOM.render(, document.getElementById('MyComponent'));

【讨论】:

以上是关于使用通过 react、redux 和 react-redux 完成的组件以及在 react 应用程序中使用 webpack 构建时出错的主要内容,如果未能解决你的问题,请参考以下文章

React-redux: React.js 和 Redux 架构的结合

react 和 Redux 的新手,为啥我会通过未定义的商店?

React: 研究React Redux的使用

React+router和react+redux使用过程的记录

在通过动作调度进行状态更新后,在 React 中使用 Redux 执行函数?

react-redux 的使用