Im Using react Komposer meteor and react .
I have this component
import React from 'react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
const lightMuiTheme = getMuiTheme(lightBaseTheme);
const Questiondetails = ({ thequestion }) => (
<div>
<MuiThemeProvider muiTheme={lightMuiTheme}>
<h4>{thequestion.header}</h4>
</MuiThemeProvider>
</div>
);
export default Questiondetails;
And this is the container
import { Meteor } from 'meteor/meteor';
import React from 'react';
import { composeWithTracker } from 'react-komposer';
import CircularProgress from 'material-ui/CircularProgress';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import Questiondetails from '../../../ui/components/Questiondetails/Questiondetails.jsx';
import Questions from '../../Collections/Questions/Questions.js';
function composer(props, onData) {
const handle = Meteor.subscribe('singleQuestion', props._id);
if (handle.ready()) {
const thequestion = Questions.findOne({ id: props._id });
onData(null, { thequestion });
}
}
const darkMuiTheme = getMuiTheme(darkBaseTheme);
const MyLoading = () => (<div style={{ width: '90%', position: 'relative' }}>
<MuiThemeProvider muiTheme={darkMuiTheme}>
<div style={{ margin: 'auto', right: 0, left: 0, maxWidth: 200, position: 'relative' }}>
<CircularProgress size={1.0} />
</div>
</MuiThemeProvider>
</div>);
export { MyLoading };
export default composeWithTracker(composer, MyLoading)(Questiondetails);
Im getting Exception from Tracker recompute function:
debug.js:41TypeError: Cannot read property 'header' of undefined
What could I be doing.
When I look over at meteor toys. I get to see the subscription in the component.
This is my publication
import { Meteor } from 'meteor/meteor';
// import the db
import Questions from '../../../../api/Collections/Questions/Questions.js';
// the publish
Meteor.publish('singleQuestion', function(id){
return Questions.find({ _id: id });
});
It is likely that you don't get the data record.
Even after the subscription handle is ready, it is possible that the query returns undefined, either because there is no data in the collection or if your query is wrong.
In this case, it seems that the query is indeed wrong, leading to you passing undefined to the component instead of the expected object.
If you provide a string as the first argument to find() or findOne(), it is assumed that you mean the _id, so it prevents errors like the (common) one you made (Questions.findOne({ id: props._id }), using the id key instead of _id).
You can use the error argument in order to catch such cases more easily (and show a meaningful error message in case something is actually wrong).
I also suggest changing thequestion to simply be question or theQuestion (more readable), unless there is a very good reason not to.
function composer(props, onData) {
const handle = Meteor.subscribe('singleQuestion', props._id);
if (handle.ready()) {
const question = Questions.findOne(props._id);
let error = null;
if (!question) {
error = new Error('no question matches the provided id');
}
onData(error, {question});
}
}
Related
I have a React/TypeScript Component that I'm trying to import mock data into and then iterate over it to display a specific attribute in a span element.
The issues I'm running into are that I can't seem to pass the mock data into my component to iterate over it and at the same time I'm also getting weird type errors that seem to suggest that I'm either using the type definitions of my data or the data itself for my props but never both.
I created a CodeSandbox to highlight these issues and I included my main component where I'm seeing the errors below:
Current Component
import React from 'react';
import contacts from '../../mock-data/contacts-mock-data';
import { Contacts, ContactGroup } from '../../services/contacts-client';
type Props = {
contacts: Contacts[];
contactGroups: ContactGroup[];
};
export const ContactGroupsSection = (props: Props) => {
const { contacts, contactGroups } = props
let groups = () => {
for (let i = 0; i < contacts.contactGroups.length; i++) {
return <span>{contacts.contactGroups.contactGroup}</span>;
}
};
return (
<div>{groups}</div>
);
};
I tweaked your codesandbox to pass the data into your component as you suggested.
App.js
import React from "react";
import "./styles.css";
import { ContactGroupsSection } from "./contact-groups";
import contacts from "./contacts-mock-data";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<ContactGroupsSection contacts={contacts} />
</div>
);
}
contact-groups.tsx
import React from "react";
import { Contacts } from "./contact-types";
type Props = {
contacts: Contacts;
};
export const ContactGroupsSection = ({ contacts }) => {
const groups = contacts.contactGroups.map(contactGroup => (
<span>{contactGroup.contactGroup}</span>
));
return <div>{groups}</div>;
};
Hope that helps!
I'm struggling to understand how to proceed with a small React app I am making.
I have a budget tracker, where you can add costs (mortgage, bills etc.) and they have a cost value. Each time you add, edit or delete one of these, I want the global state to change, which is stored in a context.
I basically have a 'remaining balance' value, that I want to recalculate each time something changes.
I figured I'd use a life cycle method or useEffect, but when I use that in my App.js (so that it watches for changes in all subcomponents), I can't get it to work, because the life cycle method is calling a method from my Context, but because it's not wrapped in the provider, it can't access the method in the Context.
Is this a common problem and is there are recommended way to fix it? I can't seem to find a similar problem on the GoOgLe.
App.js:
import React, { useState, useContext, useEffect } from "react";
import "./css/main.css";
import Header from "./layout/Header";
import BudgetInfo from "./components/BudgetInfo";
import PaymentForm from "./components/PaymentForm";
import CostToolbar from "./components/CostToolbar";
import Costs from "./components/Costs";
import BudgetContext from "./context/budgetContext";
import BudgetState from "./context/BudgetState";
const App = () => {
const budgetContext = useContext(BudgetContext);
const { updateBalance } = budgetContext;
useEffect(() => {
updateBalance();
});
return (
<BudgetState>
<Header darkModeToggle={toggleDarkMode} />
<main
className={"main-content" + (darkMode.darkMode ? " dm-active" : "")}
>
<div className="wrap content-wrap">
<BudgetInfo />
<PaymentForm />
<CostToolbar />
<Costs />
</div>
</main>
</BudgetState>
);
};
export default App;
You need to wrap the App component. Try the simple example.
import React, { useEffect, useContext } from 'react';
import ThemeContext from './../context/context';
const Sample = () => {
const context = useContext(ThemeContext);
useEffect(() => {
console.log(context,'--')
},[])
return(
<ThemeContext.Consumer>
{color => (
<p style={{ color }}>
Hello World
</p>
)}
</ThemeContext.Consumer>
)
}
export default Sample;
So I'm trying to pass a field from a MongoDB into a React Component as such:
import React from 'react';
import ReactDOM from 'react-dom';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { Players } from './../imports/api/players';
import TitleBar from './../imports/UI/TitleBar';
import AddPlayer from './../imports/UI/AddPlayer';
import Player from './../imports/UI/Player';
const renderPlayers = (playersList) => {
return playersList.map((player) => {
return <Player key={player._id} />;
});
};
But the component isn't able to read the passed in player._id value.
import React from 'react';
import { Players } from './../api/players';
export default class Player extends React.Component {
render() {
return (
<p key={this.props.player._id}>
{this.props.player.name} has {this.props.player.score} point(s).
<button onClick={() => {Players.update(this.props.player._id, { $inc: { score: 1 } });}}>+1</button>
<button onClick={() => {Players.update(this.props.player._id, { $inc: { score: -1 } });}}>-1</button>
<button onClick={() => Players.remove(this.props.player._id)}>x</button>
</p>
);
}
}
Functionality wise - the code works as intended - just not as a component here because player._id isn't able to be passed in. How do I go about passing the player._id field in properly?
Error: TypeError: Cannot read property '_id' of undefined
I thought it might be because there was no data entries in the DB - but I made sure to make a few beforehand and test that, didn't work unfortunately.
In order to use _id or fields of the player object in the child component, you should pass a player object as props to child component from the Parent component. Check the modified code below
const renderPlayers = (playersList) => {
return playersList.map((player) => {
return <Player key={player._id} player={player} />;
});
}
then your child component will work fine.
I am implementing an upload file dropzone within my react web application using react-dropzone, which I intend to send a post request to my .NET Core Web API to parse the file and save it to a DB. I am using this tutorial as a guide whilst making my own adjustments to suit my project spec, and I keep getting the below error which I am unsure how to fix:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of Upload.
This error stops the application from rendering the component.
I have researched the error and found the following answers however I believe they are unrelated to my issues.
https://github.com/ReactTraining/react-router/issues/2220
https://codereviewvideos.com/blog/warning-react-createelement/
Please see my Upload component below:
import React, { PropTypes, Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import Dropzone from 'react-dropzone';
import FontIcon from 'material-ui/FontIcon';
import { blue500 } from 'material-ui/styles/colors';
import { PageHeader, Panel } from 'react-bootstrap';
const request = require('superagent');
const apiBaseUrl = 'http://localhost:5000/api/';
const style = {
margin: 15,
};
const title = 'Upload';
class Upload extends Component {
constructor(props, context) {
super(props);
this.state = {
filesPreview: [],
filesToBeSent: [],
printcount: 10,
};
context.setTitle(title);
}
onDrop(acceptedFiles) {
console.log('Accepted files: ', acceptedFiles[0].name);
const filesToBeSent = this.state.filesToBeSent;
if (filesToBeSent.length < this.state.printcount) {
filesToBeSent.push(acceptedFiles);
const filesPreview = [];
Object.keys(filesToBeSent).forEach((key, i) => {
filesPreview.push(<div>
{filesToBeSent[i][0].name}
<MuiThemeProvider>
<a href=""><FontIcon
className="material-icons customstyle"
color={blue500}
styles={{ top: 10 }}
>clear</FontIcon></a>
</MuiThemeProvider>
</div>
);
});
this.setState({ filesToBeSent, filesPreview });
} else {
alert('You have reached the limit of printing files at a time');
}
}
handleClick(event) {
console.log('handleClick: ', event);
const self = this;
console.log('self: ', self);
if (this.state.filesToBeSent.length > 0) {
const filesArray = this.state.filesToBeSent;
const req = request.post(`${apiBaseUrl}fileupload`);
Object.keys(filesArray).forEach((key, i) => {
console.log('files', filesArray[i][0]);
req.attach(filesArray[i][0].name, filesArray[i][0]);
req.end((err, res) => {
if (err) {
console.log('error ocurred');
}
console.log('res', res);
alert('File printing completed');
});
});
} else {
alert('Please upload some files first');
}
}
render() {
return (
<div>
<div className="row">
<div className="col-lg-12">
<PageHeader>Upload Data</PageHeader>
</div>
</div>
<div className="row">
<div className="col-lg-12 col-md-8 col-sm-4">
<Panel
header={<span>
<i className="fa fa-location-arrow fa-fw" /> Drag
and drop your file here, or use the file browser:
</span>}
>
<div className="App col-lg-6 col-md-4 col-sm-2">
<Dropzone onDrop={(files) => this.onDrop(files)}>
<div>Try dropping some files here, or click to select files to upload.</div>
</Dropzone>
</div>
<div className="col-lg-6 col-md-4 col-sm-2">
Files to be printed are:
{this.state.filesPreview}
</div>
<MuiThemeProvider>
<RaisedButton
label="Print Files" style={style}
onClick={(event) => this.handleClick(event)}
/>
</MuiThemeProvider>
</Panel>
</div>
</div>
</div>
);
}
}
Upload.contextTypes = { setTitle: PropTypes.func.isRequired };
export default Upload;
Thanking you in advance. Any help is greatly appreciated.
Your import for RaisedButton is wrong. It should be
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
The import for PageHeader is also wrong. It should be
import { PageHeader, Panel } from 'react-bootstrap';
With your current imports it doesn't find RaisedButton and PageHeader.
To find the problems I've temporarily added log statements to the render method:
render() {
console.log("Panel", panel);
console.log("MuiThemeProvider", MuiThemeProvider);
//... for all components
return (
//...
);
}
As to the question: "when do I import React from 'react';" versus "when do I import { Component } from 'react';:
This depends on the module that your are trying to import and how it exports the things it exports. See export and import for the details.
A module can have one (and only one) "default export" (but it does not need do provide a default exprort!) and an arbitrary number of "named exports".
Whatever it is that the module exports with export default ...;, you can import that with import MyName from 'someModule';. Basically you are free to choose MyName to your liking, however it might confuse readers of your code if your choosen name doesn't match their expectations. And for example the JSX transpiler requires that you do the import as import React from 'react';.
For all the other things that a module exports (by name), you have to write an import statement like import { Component } from 'react'; - the module exports Component under that name, and if you want to import Component you have to name it explicitly.
I’m trying to implement the pagination on newest Meteor 1.5.2
I get the message infinity below (message repeat again and again til cpu high):
TypeError: Cannot read property 'ready' of null
at GridPaging.setDisplayedPages (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:120887)
at GridPaging.componentWillReceiveProps (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:120871)
at modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:18243
at measureLifeCyclePerf (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:17708)
at ReactCompositeComponentWrapper.updateComponent (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:18242)
at ReactCompositeComponentWrapper.receiveComponent (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:18179)
at Object.receiveComponent (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:10730)
at Object.updateChildren (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:17442)
at ReactDOMComponent._reconcilerUpdateChildren (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:16976)
at ReactDOMComponent._updateChildren (modules.js?hash=2655cfff73e00fd13ccdff98af126d1e173cbf87:17080)
Please help to find out the solution, my codes are below:
ui/pages/ReactiveRegisters.js user interface
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { Link } from 'react-router-dom';
import { Row, Col, Button } from 'react-bootstrap';
import { createContainer } from 'meteor/react-meteor-data';
import { Registers } from '../../api/registers';
import BootstrapPaginator from 'react-bootstrap-pagination';
import Loading from '../../components/Loading';
class ReactiveRegisters extends Component {
constructor(props) {
super(props);
}
renderRegister(register) {
return (
<li key={register._id}>{register.firstname}</li>
);
}
render() {
return ( !this.props.loading ? (
<div>
<ul>
{this.props.registers.map(this.renderRegister)}
</ul>
<BootstrapPaginator
pagination={this.props.pagination}
limit={10}
containerClass="text-center"
/>
</div>
) : <Loading />);
}
}
ReactiveRegisters.propTypes = {
registers: PropTypes.array.isRequired,
loading: PropTypes.bool.isRequired,
pagination: PropTypes.object,
};
export default createContainer(() => {
pagination = new Meteor.Pagination(Registers, {
filters: {},
sort: {},
perPage: 10,
reactive: true,
debug: true,
});
return {
loading: !pagination.ready(),
registers: pagination.getPage(),
};
}, ReactiveRegisters);
server/publications.js to publish the collection.
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { Events } from '../events';
import { Registers } from '../registers';
import { publishPagination } from 'meteor/kurounin:pagination'
publishPagination(Registers);
api/registers.js to define the collection.
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';
export const Registers = new Mongo.Collection('registers');
Meteor.method({........
Just read the error message - it is telling you:
Cannot read property 'ready' of null
Look for ready in your code and it will show you where it might have happened. There is only one place in the code you posted, so it means that the pagination variable is null, ie the call to new Meteor.Pagination didn't return anything.
So your pagination isn't working (as #styx suggests) - probably a problem in your publish and subscribe code. You should be able to work it out from there.
You can save yourself a lot of time posting here if you
Read the error messages and interpret them
Write defensive code that checks the returns of function calls.
These are basic programming techniques you should be following if you want to become an adept programmer