Maybe I'm missing something here, but I'm not getting data flowing from my db into my component.
I'm using react and meteor (w/ mantra), using simpleSchema/collection2 on the server. As far as I can tell I've got my publish/subscribe setup properly.
I've built things out with the mantra cli. (Which by the way is awesome)
Heres's my setup:
Component: (client/modules/components/sidebar_hubs.js)
import React from 'react';
const renderIfData = ( hubs ) => {
if ( hubs && hubs.length > 0 ) {
return hubs.map( ( hub ) => {
return <li key={ hub._id }>{ hub.name }</li>;
});
} else {
return <p>No hubs yet!</p>;
}
};
const SidebarHubs = ({hubs}) => (
<div>
<h1> Hubs </h1>
{hubs.length}
<ul> { renderIfData( hubs ) } </ul>
</div>
);
export default SidebarHubs;
Container (client/modules/containers/sidebar_hubs.js)
import {useDeps, composeAll, composeWithTracker, compose} from 'mantra-core';
import SidebarHubs from '../components/sidebar_hubs.js';
export const composer = ({context}, onData) => {
const {Meteor, Collections} = context();
const subscription = Meteor.subscribe( 'hubs' );
if ( subscription.ready() ) {
const hubs = Collections.Hubs.find().fetch();
onData( null, { hubs } );
}
};
export const depsMapper = (context, actions) => ({
context: () => context
});
export default composeAll(
composeWithTracker(composer),
useDeps(depsMapper)
)(SidebarHubs);
Publication:(server/publications/hubs.js)
import {Hubs} from '/lib/collections';
import {Meteor} from 'meteor/meteor';
import {check} from 'meteor/check';
export default function () {
Meteor.publish('hubs', function () {
return Hubs.find();
});
}
What am I missing obvious here?
This confusing to debug as nothing was breaking... And the component was being rendered, just without data.
Tossed a couple of console.logs around and it seemed like my container wasn't even being ran. As I figured it was something obvious ugh.... In my main_layout.js file.
From
import SidebarHubs from '../components/sidebar_hubs.js';
to:
import SidebarHubs from '../containers/sidebar_hubs.js';
Works like a charm now. Good debugging skills go a long way...
Related
I'm currently making a simple web frontend with react using react-autosuggest to search a specified user from a list. I want to try and use the Autosuggest to give suggestion when the user's type in the query in the search field; the suggestion will be based on username of github profiles taken from github user API.
What I want to do is to separate the AutoSuggest.jsx and then import it into Main.jsx then render the Main.jsx in App.js, however it keeps giving me 'TypeError: _ref2 is undefined' and always refer to my onChange function of AutoSuggest.jsx as the problem.
Below is my App.js code:
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import Header from './views/header/Header';
import Main from './views/main/Main';
import Footer from './views/footer/Footer';
const App = () => {
return (
<>
<Header/>
<Main/> <- the autosuggest is imported in here
<Footer/>
</>
);
}
export default App;
Below is my Main.jsx code:
import React, { useState } from 'react';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import axios from 'axios';
import { useEffect } from 'react';
import AutoSuggest from '../../components/AutoSuggest';
const Main = () => {
const [userList, setUserList] = useState([]);
useEffect(() => {
axios.get('https://api.github.com/users?per_page=100')
.then((res) => setUserList(res.data))
.catch((err) => console.log(err));
}, [])
return (
<Container>
<br/>
<Row>
<AutoSuggest userList={userList} placeHolderText={'wow'} />
</Row>
</Container>
);
}
export default Main;
Below is my AutoSuggest.jsx code:
import React, { useState } from "react";
import Autosuggest from 'react-autosuggest';
function escapeRegexCharacters(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function getSuggestions(value, userList) {
const escapedValue = escapeRegexCharacters(value.trim());
if (escapedValue === '') {
return [];
}
const regex = new RegExp('^' + escapedValue, 'i');
return userList.filter(user => regex.test(user.login));
}
function getSuggestionValue(suggestion) {
return suggestion.name;
}
function renderSuggestion(suggestion) {
return (
<span>{suggestion.name}</span>
);
}
const AutoSuggest = ({userList, placeHolderText}) => {
const [value, setValue] = useState('');
const [suggestions, setSuggestions] = useState([]);
const onChange = (event, { newValue, method }) => { <- error from console always refer here, I'm not quite sure how to handle it..
setValue(newValue);
};
const onSuggestionsFetchRequested = ({ value }) => {
setValue(getSuggestions(value, userList))
};
const onSuggestionsClearRequested = () => {
setSuggestions([]);
};
const inputProps = {
placeholder: placeHolderText,
value,
onChange: () => onChange()
};
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={() => onSuggestionsFetchRequested()}
onSuggestionsClearRequested={() => onSuggestionsClearRequested()}
getSuggestionValue={() => getSuggestionValue()}
renderSuggestion={() => renderSuggestion()}
inputProps={inputProps} />
);
}
export default AutoSuggest;
The error on browser (Firefox) console:
I have no idea what does the error mean or how it happened and therefore unable to do any workaround.. I also want to ask if what I do here is already considered a good practice or not and maybe some inputs on what I can improve as well to make my code cleaner and web faster. Any input is highly appreciated, thank you in advance!
you have to write it like this... do not use the arrow function in inputProps
onChange: onChange
I have a file (in this case Test.js) that will have many small components in the future (at the moment just Test and SuperTest).
I don't want to import the whole file in order to optimize performance. I try to import just the component I need. Not the whole file.
In the example, prop can be either "Test" or "SuperTest".
It throws an error Unexpected token (7:26)
Is there any way to accomplish that? and then render that into App?
App.js
import { useState } from 'react';
// import Test from './Test';
function App({prop}) {
const [Comp, setComp] = useState(null);
import('./Test').then(({`${prop}`: newComp}) => { // This is an ERROR
console.log(typeof newComp); // Object
setIcon(() => newComp);
});
return (
<div className="App">
<Comp />
</div>
);
}
export default App;
Test.js
export const Test = () => {
return (
<div>
Hello People
</div>
);
}
export const SuperTest = () => {
return (
<div>
Hello People 2
</div>
);
}
If you want to use many functions/components in single file and have to call the function dynamically then try below code.
Add getData() function to invoke the function in Test.js file.
Test.js
const Test = () => {
return (
<div>
Hello People
</div>
);
}
const SuperTest = () => {
return (
<div>
Hello People 2
</div>
);
}
export function getData(fnName) {
switch (fnName) {
case "Test":
return Test();
default:
return SuperTest();
}
}
Call getData() function and pass your prop as parameter
App.js
import("./Test").then((fn) => {
let newComp = fn.getData({prop}));
// use above newComp value
});
don't wrap props in this {props}. try this one:
function App(prop) {
const [Comp, setComp] = useState(null);
I'm trying to do something like this;
I have a file called /components/master_layout.js and it has the following content:
import useUser from "../data/use-user";
function MasterLayout({ children }) {
const { data, error, mutate } = useUser();
if ( error ) return <div>error</div>
if ( !data && !error ) return <div>loading..</div>
return (
<div>
{children}
</div>
)
}
export default MasterLayout
In short, this layout file returns according to the response of the useuser function.
Here is an example of a page where I use this layout:
file path and name: /pages/dashboard/index.js
import MasterLayout from "../../components/master_layout";
function Dashboard() {
return (
<MasterLayout>
dashboard..
</MasterLayout>
)
}
export default Dashboard
Can I use useUser data from Layout in '/pages/dashboard/index.js' and my other pages?
The reason I want this is, I'm trying to do something like:
import MasterLayout from "../../components/master_layout";
function Dashboard({data}) {
return (
<MasterLayout>
Welcome back, {data.username}
</MasterLayout>
)
}
export default Dashboard
Do I have any other choice but to pull the useUser for each page one by one and transfer it to the master layout as
You can use HOC pattern in this case. Something like
// with-data.js
import React from "react";
import useUser from "../data/use-user";
const withData = (WrappedComponent) => {
class WithData extends React.Component {
constructor(props) {
super(props);
this.state = {
data: "",
};
}
componentDidMount() {
const { data, error, mutate } = useUser();
this.setState({data:data});
}
render() {
const { data, ...otherProps } = this.props;
return (
<WrappedComponent data={this.state.data}/>
)
//* See how we can enhance the functionality of the wrapped component
}
}
return WithData;
};
export default withData;
Now you can use the withData,
import MasterLayout from "../../components/master_layout";
import withData from "../withData.js"
function Dashboard({data}) {
return (
<MasterLayout>
Welcome back, {data.username}
</MasterLayout>
)
}
export default withData(Dashboard);
In fact wrapping around any component with withData, can access the data variable.
I am developing a webapp to visualize some data from a remote csv. I found that react papaparse can help in this. Here is my code
import React, { useContext } from 'react';
import { DataContext } from '../context/DataContext';
import { readRemoteFile } from 'react-papaparse'
const India = () => {
const { data, dispatch } = useContext(DataContext);
const fetchData = () => {
readRemoteFile('https://www.example.com/abc.csv', {
complete: (results) => {
dispatch(
{type:'UPDATE_DATA', data:results}
)
console.log(data)
}
})
}
return(
<div className="container">
{fetchData()}
</div>
)
}
export default India;
When I run this it keeps logging the "data" object infinitely till the server returns 500 error or my system results in some error. Any way to fix it?
Below is the code for my biggest nightmare yet. I keep on getting the error that the apiData.map is not a function. Any body that can help please.
I also need to know why ApiGetData do not use react please.
I do get the api data but seems that I'm importing it incorrectly to ClassFilmData and I get the .map error. All help will be appreciated.
Tried to export films, ApiGetData in various way. Help received from other platforms was implemented but did not solve the problem. Searches - other swapi projects, import data react, sandbox, repo and other platforms
// import React from 'react';
import { ApiToGet } from "./ApiToGet";
const ApiGetData = async function() {
try {
const films = await Promise.all(
ApiToGet.map(url => fetch(url).then(resp => resp.json()))
);
console.log("film title - ", films.results);
return films;
} catch (err) {
console.log("oooooooops", err);
}
};
ApiGetData();
export default ApiGetData;
import React from "react";
import FilmsInfo from "./FilmsInfo";
const FilmsLoop = ({ apiData }) => {
return (
<div className="tc f1 unknown">
{apiData.map((answers, i) => {
return (
<FilmsInfo
key={i}
// title={ apiData.films.results[i].title }
/>
);
})}
</div>
);
};
export default FilmsLoop;
import React, { Component } from "react";
import FilmsLoop from "./FilmsLoop";
import ApiGetData from "./ApiGetData";
class ClassFilmData extends Component {
render() {
return (
<div>
<p className="tc f1">Wim - classfilmdata</p>
<FilmsLoop apiData={ApiGetData} />
</div>
);
}
}
export default ClassFilmData;
import React from "react";
const FilmsInfo = () => {
return (
<div className="tc bg-light-blue dib br3 pa3 ma3 grow bw2 shadow-5">
<p>Planet</p>
<p>FilmsInfo.js</p>
</div>
);
};
export default FilmsInfo;
That is because apiData is really ApiGetData which is a promise.
If you're trying to use the array returned by resolving this promise, you'll have to do something like this:
class ClassFilmData extends Component {
componentDidMount() {
const apiData = await ApiGetData();
this.setState({ apiData });
}
render() {
return(
<div>
<p className="tc f1">Wim - classfilmdata</p>
{this.state.apiData && <FilmsLoop apiData={ this.state.apiData }/> }
</div>
);
}
}