I am learning meteor and react from building a social network tutorial series. There a tutor had used reactjs in es5 way. He is using several mixins. For example he has used ReactMeteorData mixins with only current user fetching for Navbar and SignupForm Component and same mixin is used but fetching posts, ads and friends in Main.jsx. How could i solve this in es6 way? I have tried using react-meteor-data but confuse with same mixin with different functionality in Navbar and Main component.
Main.jsx
Main = React.createClass({
mixins: [ReactMeteorData],
getMeteorData(){
let data = {};
data.posts = [];
data.ads = [];
var friends = Meteor.user() ? Meteor.user().profile.friends : [];
friends.push(Meteor.user() ? Meteor.user()._id :'');
var posthandle = Meteor.subscribe('postlist', friends,this.state.limit);
var adhandle = Meteor.subscribe('adlist');
if(posthandle.ready()){
data.posts = Posts.find({},{sort:{createdAt:-1}}).fetch();
}
if(adhandle.ready()){
data.ads = DBAds.find({},{}).fetch();
}
return data;
}
render(){
var posts = this.data.posts.map(function (record) {
return <Post key={record._id} post={record}/>
});
return(
);
}
Navbar.jsx
Navbar = React.createClass({
getInitialState(){
return {
searchText:''
};
},
mixins: [ReactMeteorData],
getMeteorData(){
let data = {};
data.currentUser = Meteor.user();
return data;
},
render(){
var fullname = '';
if(this.data.currentUser && this.data.currentUser.profile){
fullname = this.data.currentUser.profile.firstname + ' ' + this.data.currentUser.profile.lastname;
}
return ( );
}
Now my code in es6 is
ReactMeteorDataWrap.jsx
import Navbar from './navbar/Navbar.jsx';
import { createContainer } from 'meteor/react-meteor-data';
export default createContainer(() => {
return { user: Meteor.user() };
}, Navbar);
Main.jsx
import ReactMeteorDataWrap from '../ReactMeteorDataWrap.jsx';
export default class Main extends Component {
constructor(props){
super(props);
}
render() {
// let data = this.props.getMeteorAllData();
let adobj = {_id:1, text:'My First Ad', title:'Some Company', image:'http://placehold.it/350x150' };
let posts = data.posts.map(record => {
return <Post key={record._id} post={record} />
});
return()
}
Related
I'm making this music app from online video tutorial of Simplilearn but I got this one parsing error while doing this so anyone can suggest me what to do...
did I have to change the name of the class or function?
Parsing error: identifier 'App' has already been declared
import React,{ Component } from 'react';
import './App.css';
import Playlist from '';`enter code here`
import SearchBar from '';
import SearchResults from '';
import Spotify from '';
class App extends Component() {
constructor(props) {
super(props);
this.state = {
SearchResults: [],
playlistName: "new Playlist",
playlistTracks: []
};
this.search = this.search.bind(this);
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.removeTrack.bind(this);
this.updatePlaylistName = this.updatePlaylistName.bind(this);
this.savePlaylist = this.savePlaylist.bind(this);
this.removeTrackSearch = this.removeTrackSearch.bind(this);
this.doThese = this.doThese.bind(this);
}
search(term) {
Spotify.search(term).then( SearchResults => {
this.setState({ SearchResults: SearchResults });
});
}
addTrack(track) {
let tracks = this.state.playlistTracks;
if(tracks.find( savedTrack => savedTrack.id === track.id )){
return;
}
tracks.push(track);
this.setState({ playlistTracks: tracks });
}
removeTrack(track) {
let tracks = this.state.playlistTracks;
let trackSearch = this.state.SearchResults;
tracks = tracks.filter( currentTrack => currentTrack.id !== track.id );
trackSearch.unshift(track);
this.setState({ playlistTracks: tracks });
}
removeTrackSearch(track) {
let tracks = this.state.SearchResults;
tracks = tracks.filter( currentTrack => currentTrack.id !== track.id );
this.setState({ SearchResults: tracks });
}
doThese(track) {
this.addTrack(track);
this.removeTrackSearch(track);
}
updatePlaylistName(name) {
this.setState({ updatePlaylistName: name });
}
savePlaylist() {
const trackUris = this.state.playlistTracks.map( track => track.uri );
Spotify.savePlaylist(this.state.playlistName, trackUris).then( () => {
this.setState({
updatePlaylistName: "new Playlist",
playlistTracks: []
});
});
}
}
function App() {
return (
<div>
<h1>
<a href = "https://localhost:3000" >Musicophile</a>
</h1>
<div className="App">
<SearchBar onSearch={this.search} />
<div className="App-playlist">
<SearchResults
SearchResults={this.state.SearchResults}
onAdd={this.doThese} />
<Playlist
playlistTracks={this.state.playlistTracks}
onNameChange={this.updatePlaylistName}
onRemove={this.removeTrack}
onSave={this.savePlaylist} />
</div>
</div>
</div>
);
}
export default App;
You are trying to initialize two variables (App in this case) which has the same name. Rename one of your components to something else.
Now the original question is solved, here's the hard part. There are so many things wrong with the code besides the duplicated App.
The class component App does not have a render function.
Mixing function components and class components. It will work but it is just bad practice.
State mutation. e.g.
let tracks = this.state.playlistTracks;
// ... omitted
tracks.push(track); // NO!!!!!
Unusable import statement. I'm not sure did you remove the import part deliberately or what, but if you copy and paste the imports directly, it will defiantly fail.
Using this in a function component.
Here, my componentWillReceiveProps not call. Actually what I am doing.I have 2 component but I want to show my component conditionally.
Let's talk step by step ::=>
1. Here i am using switch to call my component.
case 4 :
return(
<Hotspotmergepreview
xml = {this.state.xml}
remedStatus = {this.state.remediationToggle}
showAns = {this.showAns}
/>
);
2. Above i call hotspotmergepreview component and i pass some data(xml) using props.
this is my component where i call my both component based on conditionally.
import React from 'react';
import HotspotPreview from '../components/HotspotPreview';
import Hotspotnewpreview from '../components/Hotspotnewpreview';
export default class Hotspotmergepreview extends React.Component {
constructor(props) {
super(props)
self = this
this.cType = ''
this.state = {
xml:''
}
}
componentWillReceiveProps(nextProps) {
if(this.props.xml != nextProps.xml) {
const newXml = XMLToJSON(nextProps.xml)
this.cType = newXml.smxml.div._type
this.setState({
xml:nextProps.xml
})
}
}
render(){
if(this.cType == 'w' || this.cType == 's' || this.cType == 'p') {
console.log("inside"+this.cType)
return(
<Hotspotnewpreview
xml = {this.state.xml}
remedStatus = {this.props.remediationToggle}
showAns = {this.props.showAns}
/>
);
} else {
return (
<HotspotPreview
xml = {this.state.xml}
remedStatus = {this.props.remediationToggle}
showAns = {this.props.showAns}
/>
);
}
}
}
3. my main component where i recieve all data using componentwillreceiveprops. but this lifecycle not works properly.
export default class Hotspotnewpreview extends React.Component {
constructor(props){
super(props);
self = this
this.state ={
templateType: 'default',
}
this.templateArea = this.templateArea.bind(this)
this.checkXML = this.checkXML.bind(this)
}
componentWillReceiveProps(nextProps) {
if(this.props.xml != nextProps.xml) {
const newXml = XMLToJSON(nextProps.xml)
let cData = newXml.smxml.div.__cdata
cData = cData.replace(/%{/gm,' ').replace(/}%/gm,' ')
this.receivedXML = cData.replace(/(?:\r\n|\r|\n)/g,' <br>')
this.ansString = newXml.smxml.div._correctans
if(this.ansString) {
this.correctAnswers = this.ansString.split(',')
}
this.splitType = newXml.smxml.div._type
this.checkXML(this.splitType)
this.forceUpdate();
}
}
So i don't know what i am doing wrong here.
I'm implementing search with pagination in React. So far I found few examples of it, but all they use code with double setState(), before and after AJAX call to backend. For example my current solution is:
import React from "react"
import PropTypes from "prop-types"
import SearchField from "components/SearchField"
import SearchResults from "components/SearchResults"
import Item from "models/Item"
class Search extends React.Component {
constructor() {
super()
this.state = {
query: "",
page: 1,
foundItems: []
}
this.handleSearch = this.handleSearch.bind(this)
this.handlePageChange = this.handlePageChange.bind(this)
}
updateSearchResults() {
const query = this.state.query
const params = {
page: this.state.page
}
Item.search(query, params).then((foundItems) => {
this.setState({ foundItems })
})
}
handleSearch(event) {
this.setState({
query: event.target.value
}, this.updateSearchResults)
}
handlePageChange(data) {
this.setState({
page: data.selected + 1
}, this.updateSearchResults)
}
render() {
return (
<div className="search">
<SearchField onSearch={this.handleSearch} />
<SearchResults
onPageChange={this.handlePageChange}
onSelect={this.props.onSelect}
items={this.state.foundItems}
/>
</div>
)
}
}
Search.propTypes = {
onSelect: PropTypes.func.isRequired
}
export default Search
I know that I can change interface of updateSearchResults to receive query and page as arguments and then I can avoid first setState to pass values there, but it doesn't look like a good solution, because when list of search parameters will grow (sorting order, page size, filters for example) then it'll get a bit clumsy. Plus I don't like idea of manual state pre-management in handleSearch and handlePageChange functions in this way. I'm looking for a better implementation.
I am not fully sure what you are asking, but you can optimise your code a bit by doing the following:
class Search extends React.Component {
constructor() {
super()
this.page = 1;
this.query = "";
this.state = {
foundItems: []
}
this.handlePageChange = this.handlePageChange.bind(this)
}
updateSearchResults(event) {
if(typeof event === "object")
this.query = event.target.value;
const params = {
page: this.page
}
Item.search(this.query, params).then((foundItems) => {
this.setState({ foundItems })
})
}
handlePageChange(data) {
this.page = data.selected + 1;
this.updateSearchResults();
}
render() {
return (
<div className="search">
<SearchField onSearch={this.updateSearchResults} />
<SearchResults
onPageChange={this.handlePageChange}
onSelect={this.props.onSelect}
items={this.state.foundItems}
/>
</div>
)
}
}
I am trying to navigate between two screen with the help of react-navigation. I am able to access navigate inside the render method as its scope is also inside that method.
Where should I declare so I can access it any method of this component. I am trying to access navigate inside the onPressButton method but it giving an error.
Can't find variable: navigate
import React, { Component } from "react";
import { View, Text, Image, Button, Alert, StyleSheet } from "react-native";
import styles from "./Styles";
import * as strings from "./Strings";
import RoundButton from "./RoundButton";
var DialogAndroid = require("react-native-dialogs");
import { StackNavigator } from "react-navigation";
export default class CreateMessageScreen extends Component {
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require("./img/create_message.png")} />
<Text style={styles.textStyle}>{strings.create_message}</Text>
<RoundButton
textStyle={styles.roundTextStyle}
buttonStyle={styles.roundButtonStyle}
onPress={this.onPressButton}
>
CREATE MESSAGE
</RoundButton>
</View>
);
}
onPressButton() {
var options = {
title: strings.app_name,
content: strings.create_message,
positiveText: strings.OK,
onPositive: () => navigate("DashboardScreen")
};
var dialog = new DialogAndroid();
dialog.set(options);
dialog.show();
}
}
You need to move const { navigate } = this.props.navigation; into the onPressButton function instead of the render function (don't forget to bind the function so that this has the correct value):
export default class CreateMessageScreen extends Component {
constructor() {
super();
// need to bind `this` to access props in handler
this.onPressButton = this.onPressButton.bind(this);
}
render() {
return (
<View style={styles.container}>
<Image source={require("./img/create_message.png")} />
<Text style={styles.textStyle}>{strings.create_message}</Text>
<RoundButton
textStyle={styles.roundTextStyle}
buttonStyle={styles.roundButtonStyle}
onPress={this.onPressButton}
>
CREATE MESSAGE
</RoundButton>
</View>
);
}
onPressButton() {
const { navigate } = this.props.navigation;
var options = {
title: strings.app_name,
content: strings.create_message,
positiveText: strings.OK,
onPositive: () => navigate("DashboardScreen")
};
var dialog = new DialogAndroid();
dialog.set(options);
dialog.show();
}
}
Object destructuring work like this,
Destructuring objects:
const obj = { first: 'Jane', last: 'Doe' };
const {first: f, last: l} = obj;
// f = 'Jane'; l = 'Doe'
// {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Jane'; last = 'Doe'
In Your Case:
1. const { navigation:navigate } = this.props;
or:
2. const {navigation} = this.props;
export default class CreateMessageScreen extends Component {
render() {
const { navigation:navigate } = this.props;
return (
<View style={styles.container}>
<Image source={require("./img/create_message.png")} />
<Text style={styles.textStyle}>{strings.create_message}</Text>
<RoundButton
textStyle={styles.roundTextStyle}
buttonStyle={styles.roundButtonStyle}
onPress={this.onPressButton}
>
CREATE MESSAGE
</RoundButton>
</View>
);
}
onPressButton() {
const { navigation:navigate } = this.props;
var options = {
title: strings.app_name,
content: strings.create_message,
positiveText: strings.OK,
onPositive: () => navigate("DashboardScreen")
};
var dialog = new DialogAndroid();
dialog.set(options);
dialog.show();
}
}
That happens because you are not destructuring it from the props as you have done in your render() function
onPressButton = () => {
var {navigate} = this.props.navigation;
var options = {
title: strings.app_name,
content: strings.create_message,
positiveText: strings.OK,
onPositive: () => navigate("DashboardScreen")
};
var dialog = new DialogAndroid();
dialog.set(options);
dialog.show();
}
For those looking for the hooks version in react-navigation v6 👇🏼
import {useNavigation} from '#react-navigation/native
then inside the components call the hook
const someFunction = () => {
const navigate = useNavigation() 👈🏼
}
Apologies if the question is confusing. Basically I have this html code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A Gentle Introduction</title>
<script
src="https://rawgit.com/flatiron/director/master/build/director.min.js">
</script>
<script>
var author = function () { console.log("author"); };
var books = function () { console.log("books"); };
var viewBook = function (bookId) {
console.log("viewBook: bookId is populated: " + bookId);
};
var routes = {
'/author': author,
'/books': [books, function() {
console.log("An inline route handler.");
}],
'/books/view/:bookId': viewBook
};
var router = Router(routes);
router.init();
</script>
</head>
<body>
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
</ul>
</body>
</html>
which is clearly in a .html file. I want to change this to a .js file so that I can put html within the js so that when the different links are clicked, what is routed/returned is different.
I dont really know how to directly put this into a javascript file and then get the router to work. This is where the html file came from https://github.com/flatiron/director#client-side-routing and I am trying to use this flatiron/director router.
Any help would be great!
I was able to make it work with react and jsx and the routing code outside react itself.
Written with es6/es2015
app.js
const author = () => { console.log("author"); };
const books = () => { console.log("books"); };
const viewBook = (bookId) => { console.log("viewBook: bookId is populated: " + bookId); };
const routes = {
'/author': author,
'/books': [books, () => { console.log("An inline route handler."); }],
'/books/view/:bookId': viewBook
};
const router = Router(routes);
router.init();
class SampleRouting extends React.Component {
render() {
return (
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
</ul>
)
}
}
React.render( <SampleRouting/> , document.getElementById('root'));
index.html
<div id="root"></div>
sample: http://s.codepen.io/oobgam/debug/vNoogO
_edited app.js to reflect the updating of state and page header
class App extends React.Component {
constructor(props) {
super(props);
this.state = { currentPage: 'author' }
}
componentDidMount() {
const author = () => { this.setState({currentPage: 'author'}) };
const books = () => { this.setState({currentPage: 'Books'}); };
const viewBook = (bookId) => { this.setState({currentPage: 'Book ' + bookId }); };
const routes = {
'/author': author,
'/books': books,
'/books/view/:bookId': viewBook
};
const router = Router(routes);
router.init();
}
render() {
return (
<div>
<h1>{ this.state.currentPage }</h1>
<SampleRouting />
</div>
);
}
}
// stateless function
const SampleRouting = () => {
return (
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
< /ul>
)
}