React Meteor 似乎无法传递道具

React Meteor cannot seem to pass props

所以我一直在尝试自学 react 和 meteor 来创建应用程序。由于这是我第一次真正深入研究这个 material,所以我可能遗漏了一些非常简单的东西。完整代码可以在 https://github.com/Afro523/MineralID-Meteor.

找到

我在 mongo 中有一个名为 Minerals 的 collection,我很确定数据本身通过观看流星开发工具 ddp 和 mini[=42 从发布加载到订阅=].

我正在使用 React 路由器转到 ListPage.jsx,然后加载我的 collection 矿物。我 运行 我的代码(如下)并得到 "Uncaught TypeError: Cannot read property 'minName' of undefined"

我希望我提供了足够详细的情况,非常感谢任何和所有建议。先谢谢你了!

ListPage.jsx 即着陆页

import React, { Component, PropTypes } from 'react';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import {List} from 'material-ui/List';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import NavigationClose from 'material-ui/svg-icons/navigation/close';
import {Link} from 'react-router';
import {createContainer} from 'meteor/react-meteor-data';
import {Meteor} from 'meteor/meteor';
import {Minerals} from '../../api/minerals';

import MinList from './MinList';

// App component - represents the whole app
export class ListPage extends Component {

    constructor(props) {
        super(props);
    }
    getChildContext() {
        return { muiTheme: getMuiTheme(baseTheme) };
    }

    renderMinerals () {
        return  this.props.minerals.map((mineral) => (

            <MinList key={mineral._id} mineral={mineral}/>
        ));
    }

    render() {

        return (
                <div className="container">
                    <AppBar
                        iconElementLeft={<IconButton><Link to="/"><NavigationClose/></Link></IconButton>}
                        title="Mineral ID"
                    />
                    <List>

                        {   this.renderMinerals()   }
                    </List>
                </div>
        );
    }
}

ListPage.propTypes = {
    minerals: PropTypes.array.isRequired,

};

export default createContainer(()=>{
    if (Meteor.subscribe('minerals').ready()){
        return{
            minerals: Minerals.find({}, {sort: {name: 1}, limit:10}).fetch(),
        };
    } else {
        return{
            minerals: null
        };
    }
}, MinList);

ListPage.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};

MinList.jsx

import React, {Component, PropTypes} from 'react';
import {ListItem} from 'material-ui/List';
import Avatar from 'material-ui/Avatar';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import MinCard from './MinCard';

const customContentStyle = {
    width: '95%',
    maxWidth: 'none',
};

export default class MinList extends Component {
    constructor(props) {
        super(props);
        //Setting up state for dialog
        this.state = {
            open:false
        };
    }

    handleOpen() {
        this.setState({open: true});
    }

    handleClose() {
        this.setState({open: false});
    }

    render() {
        const mineral =  this.props.mineral;
        const actions = [
            <FlatButton
             label="Close"
             primary={true}
             onTouchTap={this.handleClose.bind(this)}
            />,
        ];
        return (
            <div>
                <ListItem
                    primaryText={mineral.minName}
                    leftAvatar={<Avatar src={'./img/'+mineral.minName+'.jpg'}/>}
                    secondaryText={mineral.formula}
                    onTouchTap={this.handleOpen.bind(this)}
                />
                <Dialog
                    title={mineral.minName}
                    leftAvatar={<Avatar src="minImage.jpg"/>}
                    actions={actions}
                    modal={false}
                    open={this.state.open}
                    onRequestClose={this.handleClose.bind(this)}
                    autoScrollBodyContent={true}
                    contentStyle={customContentStyle}
                >
                <MinCard mineral={mineral}/>
                </Dialog>
        </div>
        );
    }
}

MinList.propTypes ={
    minerals: PropTypes.array.isRequired,
    mineral : PropTypes.object.isRequired,
};

MinCard.jsx 最低级组件

import React, {Component, PropTypes} from 'react';
import {Card, CardMedia, CardText} from 'material-ui/Card';
import {Table, TableBody, TableRow, TableRowColumn} from 'material-ui/Table';

const tableStyle={
    fontSize: '15px',
};


export default class MinCard extends Component {

    render() {
        const mineral = this.props.mineral;
        return (
      <Card>
                <CardMedia mediaStyle={{height: '50%', width: '50%', margin: 'auto'}}>
                <img src={'./img/'+this.props.mineral.minName+'.jpg'}/>
                </CardMedia>
                <CardText>
                    <h5>Summary</h5>
          {mineral.summary}
        </CardText>
                <Table>
                    <TableBody
                        displayRowCheckbox={false}
                        >
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Formula
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.formula}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Crystal System
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.crystalSystem}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Crystal Habit
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.crystalHabit}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Cleavage
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.cleavage}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Luster
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.luster}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Color
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.color}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Streak
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.streak}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Class Type
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.classType}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Fracture
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.fracture}
                            </TableRowColumn>
                        </TableRow>
                        <TableRow
                            selectable={false}
                            >
                            <TableRowColumn style={tableStyle}>
                                Hardness
                            </TableRowColumn>
                            <TableRowColumn style={tableStyle}>
                                {mineral.hardness}
                            </TableRowColumn>
                        </TableRow>
                    </TableBody>
                </Table>
      </Card>
        );
    }
}

MinCard.propTypes = {
    mineral: PropTypes.object.isRequired,
};

我认为您遇到的问题源于这段代码:

renderMinerals () {
    return  this.props.minerals.map((mineral) => (

        <MinList key={mineral._id} mineral={mineral}/>
    ));
}

您的 map 函数没有 returning 任何东西,因此 renderMinerals 函数将 return 一个 [undefined, undefined, undefined].

的数组

试试 return (<MinList key={mineral._id} mineral={mineral}/>);

编辑:另一个技巧是在 MinList 的渲染函数中放置一个断点,并检查 this.props.mineral 不是 undefined

首先感谢 Paqash 为我指明了正确的方向,问题是组件在数据可用之前安装。所以经过一番研究,我发现了这个话题 https://forums.meteor.com/t/react-component-mount-wait-for-subscriptions-ready/13646.

我需要一个 getMeteorData() 函数,从那里我可以控制订阅准备就绪和未准备好时发生的情况。由于这个功能,我还不得不将地图功能更改为 this.data.minerals,更改后的页面如下。我希望这可以帮助其他人寻找解决此问题的方法。

import React, { Component, PropTypes } from 'react';

import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import {List} from 'material-ui/List';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import NavigationClose from 'material-ui/svg-icons/navigation/close';
import {Link} from 'react-router';
import {ReactMeteorData} from 'meteor/react-meteor-data';
import {Meteor} from 'meteor/meteor';
import {Minerals} from '../../api/minerals';
import MinList from './MinList';
import ReactMixin from 'react-mixin';

export default class ListPage extends Component {

    constructor(props) {
        super(props);
    }
    getChildContext() {
        return { muiTheme: getMuiTheme(baseTheme) };
    }
    //New Function Needed
    getMeteorData(){
        const handle = Meteor.subscribe('minerals');

        return {
            ready: handle.ready(),
            minerals: Minerals.find({}, {sort: {name: 1}}).fetch(),
        };
    }

    renderMinerals () {
        return  this.data.minerals.map((mineral) => (

            <MinList key={mineral._id} mineral={mineral}/>
        ));
    }

    render() {
        //Wrapped render in if data ready bool
        if(!this.data.ready){
            return (
                <div className="container">
                    <AppBar
                        iconElementLeft={<IconButton><Link to="/"><NavigationClose/></Link></IconButton>}
                        title="Mineral ID"
                    />
                <div>Loading</div>
            </div>
            );
        } else {

            return (
                <div className="container">
                    <AppBar
                        iconElementLeft={<IconButton><Link to="/"><NavigationClose/></Link></IconButton>}
                        title="Mineral ID"
                    />
                    <List>
                        {   this.renderMinerals()   }
                    </List>
                </div>
            );
        }
    }
}

//Added
ReactMixin(ListPage.prototype, ReactMeteorData);

ListPage.propTypes = {
    minerals: PropTypes.array.isRequired,

};

ListPage.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};