React + Meteor keyed object warning - meteor

How do I get rid of this warning? If I delete task.created there is no warning. Can't figure this one out. See my code example below:
Warning: Any use of a keyed object should be wrapped in React.addons.createFragment(object) before being passed as a child.
ShowAllPosts = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
// This function knows how to listen to Meteor's reactive data sources,
// such as collection queries
return {
// Returns an array with all items in the collection
tweets: Posts.find().fetch().reverse()
}
},
render() {
var showHTML = this.data.posts.map(function (task) {
return (
<div key={task._id}>
<img className="profile-pic" src="images/puppy.jpeg" />
{task.content}
<br />
Date: {task.created}, Get Link, id: {task._id}
<hr />
</div>
);
});
return (
<ul>
<hr />
{/* Access the data from getMeteorData() on this.data */}
{ showHTML }
</ul>
);
}
});

I assume that task.created is a Date object.
React isn't casting dates to strings automatically, so you need to write something like {task.created.toString()} or use package like moment to format your date.

Related

Next.js: Passing data to nested routes

Issue:
Right now, I have a dynamic route that fetches data using getServerSideProps(). Within this page, there are multiple tabs that renders different data depending on state (which tab is selected).
I wish to transition from using multiple tabs on this page, to instead using nested routes. However, I am having difficulty obtaining the data originally fetched in these nested routes. Is there an efficient way of doing so, without having to call getServerSideProps() again?
My intended setup looks like this, where [page] calls getServerSideProps():
[page].jsx
|_tab1.jsx
|_tab2.jsx
|_tab3.jsx
My current [page].jsx, where I would like to use separate, nested pages that have access to these props (instead of rendering each tab based on state):
export default function Page(props) {
const [currentTab, setCurrentTab] = useState("home");
return (
<div>
<div id="tab1" onClick={() => setCurrentTab("home")}>
home
</div>
<div id="tab2" onClick={() => setCurrentTab("posts")}>
posts
</div>
<div id="tab3" onClick={() => setCurrentTab("info")}>
info
</div>
{currentTab === "home" ? (
<HomeTab props={props}/>
) : currentTab === "posts" ? (
<PostsTab props={props}/>
) : (
<InfoTab props={props}/>
)}
</div>
);
}
Attempts
I've attempted using the context API to utilize data globally, which my other pages can use. However, this requires the user to visit the original dynamic route first.
Call getServerSideProps() on each nested route. Although this works, I wish to find a better solution, since I'm fetching data on each nested route while the route they're nested under has all of this data available already.
You can use shallow routing in next/route or next/link
Note that, in the below example, I'm using next/link for the demonstration. Without your tab data, I'd assume you have an array of tabs in data
import { useEffect } from 'react'
import Link from 'next/link'
//the path is `/tab/:tabId`
function Tab({ data }) {
const [tabData, setTabData] = useState(data[0]) //first tab data as default for example
useEffect(() => {
setTabData(data[tabId])
}, [router.query.tabId])
return <>
<Link href="/tab/0" shallow />
<Link href="/tab/1" shallow />
<div>
{tabData}
</div>
</>
}
export async function getServerSideProps(context) {
return {
props: {
data: [], //tabs' data you fetched from the API
},
}
}
export default Tab

"Uncaught TypeError: Cannot read property 'push' of null" with Polymer 3 and polymerfire3

I'm working in a project with Polymer 3 and polymerfire3.
Right now I have been able to use firebase-auth element successfully. But now that I'm trying to use the firebase-query element I get this on the console Uncaught TypeError: Cannot read property 'push' of null
This is my code
import { PolymerElement, html } from '#polymer/polymer/polymer-element.js';
import './shared-styles.js';
import 'polymerfire3/firebase-auth.js';
import 'polymerfire3/firebase-query.js';
class PerfilView extends PolymerElement {
static get properties() {
return {
user: Object,
uid: String,
data: {
type: Object,
observer: 'dataChanged'
}
};
}
static get template() {
return html`
<firebase-auth
id="auth" user="{{user}}">
</firebase-auth>
<firebase-query
log
id="query"
app-name="morse"
path="/notes/"
data="{{data}}">
</firebase-query>
<div class="card">
<div id="notes">
<ul id="notes-list">
<template is="dom-repeat" items="{{data}}" as="note">
<li>
<p class="content">{{note}}</p>
</li>
</template>
</ul>
<paper-input value="{{inputP::input}}" label="Take a note.."></paper-input>
<div id="notes-controls">
<paper-button id="add" on-tap="add">Add</paper-button>
</div>
</div>
</div>
`;
}
add() {
this.$.query.ref.push({
content: this.inputP
});
}
}
window.customElements.define('perfil-view', PerfilView);
Does it have something to do with the polymerfire3 elements?
You will need to add polymer-document in order to add a record. Additional to your code, something like:
<firebase-document
id="document"
app-name="morse"
path="/notes/[[key]]"
data="{{edata}}">
</firebase-document>
and pushing new data may look like ;
add() {
var key = firebase.database.ref('notes').push().key;
this.set('edata', this.inputP);
this.set('key', key);
// this new Note will be syncronised upon new key and edata properties defined. Here firebase-document will keep sysnronised with edata and path.
}
firebase-query element is basically utilized for -
combining the given properties into query options that generate a
query, a request for a filtered, ordered, immutable set of Firebase
data
Here is further to read up on.
I think, what you're trying to do, can simply be achieved as follows -
add(noteData) {
let newNoteRef = firebase.app().database().ref('notes').push();
return newNoteRef.set(noteData).then(() => {
console.log(`a new note successfully added.`);
});
}
Upon successful data upsert firebase-query will automatically update data bound-variable to reflect the new list.

Does React component definetely update itself when a method is called

Although you don t need to look at the code below to understand the question, I added it in case you need to visualize the scenario. Whenever the form submits, addList method is called.
And the component updates itself. But I didn t expect this behaviour, that s why at first I did try to assign my lists to state, so that when the state changed the component would update itself as I wanted.
Anyway it already updates itself, but why ? Which way is more efficient ?
import React,{Component} from 'react';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import {Lists} from '../lib/collections/lists.js';
export default class App extends TrackerReact(Component) {
constructor(){
super();
// this.state = {lists : this.lists()}
}
lists(){
return Lists.find().fetch();
}
addList(e){
e.preventDefault();
//let text = this.refs.list.value ;
let text = this._inputList.value ;
console.log(this._inputList.value);
Lists.insert({
title : text
});
this._inputList.value = "";
//this.setState({lists : this.lists()});
}
render() {
return (
<div>
<h2>Lists</h2>
<ul>
{this.lists().map((a,b)=>(
<List key={a._id} title={a.title} />
))}
</ul>
<form onSubmit={this.addList.bind(this)}>
<input
type="text"
ref={(input)=>{
this._inputList = input ;
}}
placeholder="add list bro"
/>
</form>
</div>
)
}
}
So if we add a componentWillUpdate react life-cycle method to see if it rerenders ;
componentWillUpdate() {
console.log('will update');
}
When form submitted "will update" is logged on console as expected. However if we update addList as ;
addList(e){
e.preventDefault();
// nothing else.
}
We don t see the output "will update" on console. Which means method being called doesn t require the component to be rerendered. There is no such a rule. In this case , it is probably about TrackerReact. TrackerReact might force the component to rerender.

Updating model value onChange in Meteor + React places cursor at the end of the string

I am using Meteor with React. Consider this simple component below. There is a local mini-Mongo collection CommentsCollection. The component will insert a row in it when componentWillMount will be called. getMeteorData will return the first record in the collection and we'll be able to modify the title. Problem: if I place my cursor at the start of the title and start typing, after the first character update the cursor will jump to the end of the string and the rest of my typing will be placed there. How do I work around this?
CommentsCollection = new Meteor.Collection(null); // Local mini-mongo collection
EventTestComponent = React.createClass({
mixins : [ReactMeteorData],
componentWillMount(){
CommentsCollection.insert({title:"test title", message:"some test message"});
},
getMeteorData(){
return {
comment: CommentsCollection.findOne()
};
},
handleTitleChange(e){
CommentsCollection.update({_id: this.data.comment._id}, {$set:{title: e.target.value}});
},
render(){
if(this.data.comment) {
return (
<div>
<input type="text" value={this.data.comment.title} onChange={this.handleTitleChange}/>
</div>
);
}else{
return <div>Loading...</div>
}
}
});
I came up with this solution right after I posted the question:
<input type="text"
defaultValue={this.data.comment.title}
onKeyUp={this.handleTitleChange}/>
So: change value to defaultValue, and onChange to onKeyUp. Works like a charm!

trying to render a list. nothing showing on screen

Using Meteor and React. Trying to render a list of data from the server onto the client. the server's data looks like this:
Searches.insert({text: data.items[i].snippet.title});
if(Meteor.isClient) {
Searches = new Meteor.Collection('searches');
Meteor.subscribe('allSearches');
}
....
renderTasks(){
return this.data.searches.map((searches) => {
return <SearchResultItem searches={searches} />;
});
},
....
<ul>
{this.renderTasks()}
</ul>
....
SearchResultItem = React.createClass({
render(){
return
<li>
{this.props.searches.text}
</li>
}
});
You need to provide an unique key-prop to your dynamic child elements
Dynamic Children
The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a key:
render: function() {
var results = this.props.results;
return (
<ol>
{results.map(function(result) {
return <li key={result.id}>{result.text}</li>;
})}
</ol>
);
}
(REF: https://facebook.github.io/react/docs/multiple-components.html#dynamic-children)
In your case:
renderTasks(){
return this.data.searches.map((searches, i) => {
return <SearchResultItem key={i} searches={searches} />;
});
}

Resources