I'm trying to build a todo app on Meteor using the new React (which is basically like learning Meteor all over again).
Anyway, I'm trying to load MongoDB data on top of this ListBox React component and using this data as props via this.props.lists, but when console logging the this and navigating to the props key, there are no props and nothing I insert to the MongoDB shows up for some reason.
Here is the code:
import React, {PropTypes} from "react";
import {List} from "./list.jsx"
import {Lists} from "/imports/api/database.js";
import { createContainer } from 'meteor/react-meteor-data';
export class ListBox extends React.Component{
_renderTasks(){
return this.props.lists.map((list) => (
<List key={list._id} task={list}/>
))
}
render(){
console.log(Lists.find({}).fetch())
return(
<div class="ui raised very padded text container segment">
<div className="ui inverted segment">
{this._renderTasks()}
</div>
</div>
)
}
}
export default createContainer(() => {
return {
lists: Lists.find({}).fetch()
};
}, ListBox);
There is no error code in my console. All packages are installed, including react-meteor-data for rendering reactive data to react components.
Related
I use the react-tooltip library in my Next.js app.
I noticed that every time I refresh a website while visiting a page that uses the tooltip I get an error:
react-dom.development.js:88 Warning: Prop `dangerouslySetInnerHTML` did not match.
CSS classes are different on the client and on the server
The weird part is I do not get that error while navigating from a random page to a page that uses the react-tooltip.
The tooltip related code:
<StyledPopularityTooltipIcon src="/icons/tooltip.svg" alt="question mark" data-tip="hello world" />
<ReactTooltip
effect="solid"
className="tooltip"
backgroundColor="#F0F0F0"
arrowColor="#F0F0F0"
clickable={true}
/>
I had the same issue, I had to use state to detect when component has been mounted, and show the tooltip only after that.
P.S. You don't see the error when navigating, because the page is not rendered on server when you navigate, it's all front-end :)
In case you are using any server-side rendering (like Next.js) - you will need to make sure your component is mounted first before showing the react-tooltip.
I fixed this by using the following:
import React, { useEffect, useState } from 'react';
const [isMounted,setIsMounted] = useState(false); // Need this for the react-tooltip
useEffect(() => {
setIsMounted(true);
},[]);
return (<div>
{isMounted && <ReactTooltip id={"mytip"} effect={"solid"} />}
<span data-tip={"Tip Here"} data-for={"mytip"}>Hover me</span>
</div>)
You should wrap your JSX in the following component:
import React, { useEffect, useState } from 'react';
const NoSsr = ({ children }): JSX.Element => {
const [isMounted, setMount] = useState(false);
useEffect(() => {
setMount(true);
}, []);
return <>{isMounted ? children : null}</>;
};
export default NoSsr;
Like this:
<NoSsr>
<YourJSX />
</NoSsr>
If you are working with NEXTJS this might be a good approach, you can check the documentation here as well, also if you are working with data-event, globalEventOff or any other prop and is not hiding or not working in your localhost, this only occurs in Development Strict Mode. ReactTooltip works fine in Production code with React 18. So you can set reactStrictMode : false, in your next.config.js to test it locally and then set it back to true, hope this helps :) info reference here
import dynamic from 'next/dynamic'
const ReactTooltip = dynamic(() => import('react-tooltip'), { ssr : false });
function Home() {
return (
<div>
<Button
data-tip
data-event="click focus"
data-for="toolTip"
onClick={():void => ()}
/>
<ReactTooltip id="toolTip" globalEventOff="click"/>
</div>
)
}
export default Home
I want to create copy to clip board using react js but i design like
textbox with in contain 'copy' word ,when i click this copy word it changed to be copied
and the textbox value will be copied
You can do this by using ref, document.execCommand('copy').
import React from 'react';
class CopyExample extends React.Component {
constructor(props) {
super(props);
this.state = { copySuccess: '' }
}
copyToClipboard = (e) => {
this.textArea.select();
document.execCommand('copy');
e.target.focus();
this.setState({ copySuccess: 'Copied!' });
};
render() {
return (
<div>
{
document.queryCommandSupported('copy') &&
<div>
<button onClick={this.copyToClipboard}>Copy</button>
{this.state.copySuccess}
</div>
}
<form>
<textarea
ref={(textarea) => this.textArea = textarea}
value='Some text to copy'
/>
</form>
</div>
);
}
}
export default CopyExample;
For clipboard interaction in React, I use clipboard-polyfil. It is nice because it provides polyfills to work on all browsers, which some of the native clipboard functions do not, such as document.execCommand("copy") and navigator.clipboard.write().
The easiest way to use this package with react is to make a custom component, pass in the string you would like to copy as a prop, and copy it using clipboard.writeText(this.props.stringValue);
Personally, I'm using react-copy-to-clipboard
1- install it using npm:
npm install --save react react-copy-to-clipboard
2- import it to your file:
import {CopyToClipboard} from 'react-copy-to-clipboard';
3- now you can wrap your component with <CopyToClipboard> component
it also provide onCopy optional callback function.
resources: CopyToClipboard repo on github
i have a working component where i'm doing this:
import React, {Component, PropTypes} from 'react';
import {createContainer} from 'meteor/react-meteor-data';
export default class Foo extends Component {
}
export default createContainer(() => {
}, Foo);
import Foo from '/imports/ui/components/Foo';
i am using Blaze to wrap the React components, like this:
import Foo from '/imports/ui/components/Foo';
Template.registerHelper("Foo", function() {
return Foo;
);
<div>
{{> React component=Foo}}
</div>
i realize that i shouldn't be doing multiple default exports in a single file, but it does work. note that this is with these versions: Meteor v1.4.1.1, Meteor npm v3.10.6, Meteor node v4.5.0.
i now have a test harness, with Meteor v1.4.2.3, Meteor npm v3.10.9 and Meteor node v4.6.2, where this has stopped working. not surprisingly, in my server console:
While building for web.browser:
imports/ui/components/Foo.jsx:58: Only one default export allowed
per module. (58:0)
so now i'm looking for a way to get this back working, and in the proper way.
what i've tried:
first, keeping the component and the create container in the same file, i did proper ES6 exporting:
const Foo = class Foo extends Component {
const FooContainer = createContainer(() => {
export {Foo, FooContainer};
... and imported Foo.
result: Foo loaded in the app, but the container code never ran.
second, i put the component and the create container in two different files, and reverted to exporting defaults:
// Foo.jsx
export default class Foo extends Component {
// FooContainer.jsx
export default createContainer(() => {
... and used Foo:
import Foo from '/imports/ui/components/Foo';
Template.registerHelper("Foo", function() {
return Foo;
});
<div>
{{> React component=Foo}}
</div>
result: Foo loaded in the app, but the container code never ran.
third, similar to the above, but i instead tried putting FooContainer on the page:
import FooContainer from '/imports/ui/components/FooContainer';
Template.registerHelper("Foo", function() {
return FooContainer;
});
<div>
{{> React component=Foo}}
</div>
result: big error message from React that basically i wasn't doing it right.
any idea on the proper way to get this to work?
update:
attempts 4 and 5
put both back into same class, like this:
export class Foo extends Component {
export default createContainer(() => {
... with 2 different ways of importing it:
import Foo from '/imports/ui/components/Foo';
that ran createContainer() but did not put my component on the page.
import {Foo} from '/imports/ui/components/Foo';
that did the opposite: did not run createContainer(), but i did see the component.
got it working, in 1 jsx file:
export class Foo extends Component {
export default createContainer(() => {
in the helper, relying on the default export:
import Foo from '/imports/ui/components/Foo';
the actual problem was i had incorrectly imported a server file to publish, and that caused a chain reaction which caused the component to not render. doh.
Greetings fellow meteorites!
I am in the process of including material ui (react based) into an existing blaze app. I'm using the meteor guide and the material-ui docs as my instructions to do this properly but unfortunately to no avail. Has anyone successfully done this before? According to the material-ui docs you are supposed to inject an MuiThemeProvider into your main App Component but I keep getting the following error:
MuiThemeProvider.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Here is my root blaze html template:
<template name="main">
<head>...</head>
<body>
<div id="wrap">
<div id="react-app-wrapper">
{{> React component=App}}
</div>
</div>
</body>
</template>
Notice I am using https://guide.meteor.com/react.html#react-in-blaze as my guidelines and am using the meteor package react-template-helper.
Here is my main.js file:
if(Meteor.isClient){
import App from './users/client/ui/components/App.js';
Template.main.onCreated(function(){
});
Template.main.helpers({
'App' : function(){
return App;
}
}
And my App.js Component File:
import React, { Component, PropTypes } from 'react';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
const lightMuiTheme = getMuiTheme(lightBaseTheme);
export default class App extends Component{
constructor(props){
super(props);
}
render() {
return (
<div>
<MuiThemeProvider muiTheme={lightMuiTheme} >
</MuiThemeProvider >
</div>
);
}
}
Appreciate your help big time! I have tried everything and feeling pretty stumped right now. :( If you give the correct answer I will obviously mark it as so!
Alex
This is how MuiThemeProvider renders
render() {
return this.props.children;
}
And therefore it, React actually, complained of nothing to render since this is you use it.
render() {
return (
<div>
<MuiThemeProvider muiTheme={lightMuiTheme} >
{/* There should be something here. */}
</MuiThemeProvider >
</div>
);
}
Start to put some contents that it can serve for you.
A side notice here is that the outer <div> wrapper can be dropped on the premise that it is not of some particular use.
Good luck!
I'm using the Accounts UI meteor package in my React + Meteor project and want to render the loginButtons template with the property align="right". In Blaze the code would just be {{> loginButtons align="right"}}, but I'm at at a loss with how to add this property in React.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
export default class AccountsUIContainer extends Component {
componentDidMount() {
this.view = Blaze.render(Template.loginButtons, // How do I give loginButtons `align="right`?
ReactDOM.findDOMNode(this.refs.container));
}
componentWillUnmount() {
Blaze.remove(this.view);
}
render() {
return <span ref="container" />;
}
}
I think Blaze.renderWithData() may be part of the solution, but my tests with this method haven't worked so far. I also think people have created solutions to using Blaze templates in React before, but I'm not sure these alternate solutions would be the "right" way to solve this problem in Meteor 1.4.
The answer was right inside the documentation. First meteor add gadicc:blaze-react-component, then in the component
import React from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';
const App = () => (
<div>
<Blaze template="loginButtons" align="right" />
</div>
);