Using Meteor 1.2.0.1 and React. My simple app works great but now I needed iron router.
app layout:
client\
app.jsx
lib\
router.jsx
server
views\
home.jsx
layout.jsx
home.jsx:
Home = React.createClass({
render() {
return (
<div>
<h3>Hello World</h3>
<p>from home</p>
</div>
);
}
});
layout.jsx:
Layout = React.createClass({
render() {
return (
<div>
{this.props.children}
</div>
);
}
});
routes.jsx:
Router.route('/', () => {
let page = (
<Layout>
<Home/>
</Layout>
);
React.render(page, document.body);
});
Surely enough, in my app.jsx, works great as it displays to the body of the html but the setup would not work for a multi-page app so this is the need for routes. Inside is:
Meteor.startup(() => {
let app = (
<Layout>
<Home/>
</Layout>
);
React.render(app, document.body);
});
The question is, how to get iron router (routes.jsx) to show the contents?
I would strongly recommend using Flow Router instead of Iron Router. Add Flow Router to your app, then add kadira:react-layout as well. Follow this format and it should work:
FlowRouter.route('/', {
name: 'home',
action() {
ReactLayout.render(Layout, {content: <Home />});
}
});
FlowRouter.route('/login', {
name: 'loginPage',
action() {
ReactLayout.render(Layout, {content: <Login />});
}
});
And your Layout component should look like:
Layout = React.createClass({
render() {
return (
<div>
<Header />
{this.props.content}
</div>
);
}
});
To route to a page that takes a parameter:
FlowRouter.route('/detail/:id', {
name: 'prodDetail',
action() {
ReactLayout.render(Layout, {content: <ProdDetail />});
}
});
And then in your ProdDetail component, you can refer to FlowRouter.getParam('id'). Check out the full FlowRouter documentation.
The solution was to add the ejson package which solved the issue, thanks to Chris. But I can easily follow Flow Router so I'll mark (since I'll be using it) that the answer but for anyone that has this issue, use the ejson package. However then my resolver over time.
Related
This code is in a page file in NextJS. Although I'm not using getStaticProps or getServerSideProps it still performs server side rendering.
Is this by design? The docs would imply that these get functions are required: https://nextjs.org/docs/basic-features/data-fetching
import React from "react";
import Head from "next/head";
import Link from "next/link";
import { ApolloProvider } from "#apollo/react-hooks";
import ApolloClient from "apollo-boost";
import { gql } from "apollo-boost";
import { useQuery } from "#apollo/react-hooks";
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
});
const EXCHANGE_RATES = gql`
{
rates(currency: "USD") {
currency
rate
}
}
`;
const Home: React.FC = () => {
const { loading, error, data } = useQuery(EXCHANGE_RATES);
if (loading) {
return (
<div>
<p>Loading</p>
</div>
);
}
if (error) {
return (
<div>
<p>Error</p>
</div>
);
}
return (
<div>
<ul>
{data.rates.map((item) => (
<li key={item.currency}>
{item.currency} - {item.rate}
</li>
))}
</ul>
</div>
);
};
export default () => (
<ApolloProvider client={client}>
<Home />
</ApolloProvider>
);
Production mode
The page provided has no getInitialProps or getServerSideProps. It's statically optimized (pre-rendered at build time).
So, when you request this page in a browser, you will see a pre-rendered HTML content in the response. Disabling JavaScript does not affect it.
If you navigate to the page by using client-side next/link or router the page will be rendered at client-side without making a request to a server.
Development mode
In Development mode this page would be both - server-side rendered and client-side rendered.
If you'd request the page by typing address in a browser it will be pre-rendered at server-side.
If you navigate to the page by using client-side next/link or router the page will be rendered at client-side without making a request to a server (you will see only Webpack Hot Module Replacement request).
I'm trying to disable the toolbars for all core blocks to keep the editors from unnecessarily formatting the content. Is that even possible?
My current approach is:
wp.blocks.getBlockTypes().forEach((blockType) => {
// unregister all default styles (from the right sidebar)
let blockName = blockType.name;
if ( blockType.hasOwnProperty('styles')) {
blockType.styles.forEach( (style) => {
wp.blocks.unregisterBlockStyle( blockName, style.name );
});
}
});
Can I somehow access the toolbars in this loop? Do I understand it correctly that I have to override the edit and save methods of the core blocks, probably with a filter?
Thanks, Patrik
I have just solved the problem, but different than intended.
Basically, the solution for me was to deregister the required core blocks, make changes to the edit and save methods, and then re-register the blocks.
A great help was this blog article by Riad Benguella:
https://riad.blog/2017/10/16/one-thousand-and-one-way-to-extend-gutenberg-today/
Here's an example based on a core / quote block:
const TextControl = wp.components.TextControl;
import './style.scss';
import './editor.scss';
wp.domReady( () => {
let unregisteredBlock = wp.blocks.unregisterBlockType('core/quote');
unregisteredBlock.title = 'Quotation';
unregisteredBlock.icon = 'format-quote';
unregisteredBlock.edit = ({ attributes, setAttributes} ) => {
const updateFirstValue = ( val ) => {
setAttributes({
value: val
});
};
const updateSecondValue = ( val ) => {
setAttributes({
citation: val
});
};
return (
<div>
<TextControl
label='Quote'
value={ attributes.value }
onChange={ updateFirstValue }
/>
<TextControl
label='Citation'
value={ attributes.citation }
onChange={ updateSecondValue }
/>
</div>
);
};
unregisteredBlock.save = ( { attributes, className } ) => {
return (
<blockquote className={className}>
<p>{attributes.value}</p>
<cite>{attributes.citation}</cite>
</blockquote>
)
};
wp.blocks.registerBlockType('core/quote', unregisteredBlock);
});
In principle, both the edit and save method are replaced here, only the block attributes are reused from the core blocks. Due to the fact that new elements are used to enter the content, the toolbars are not the problem anymore.
I hope this can help someone who has the same problem.
Cheers,
Patrik
I'm trying to just get off the ground with Meteor 1.2.1 and am failing miserably.
I've simply used the code from this question but always receive a blank page. If I remove the Button class, there's no problem with getting the div to appear or text inside it.
I receive no console errors.
My added packages:
twbs:bootstrap 3.3.6
universe:react-bootstrap 0.24.0
react 0.14.3*
Code:
if (Meteor.isClient) {
Meteor.startup(function () {
let App=React.createClass({
render: function () {
return (
<div>
<Button>Default</Button>
</div>
);
}
});
React.render(<App/>, document.getElementById("container"));
});
}
I expect that whatever I'm missing is very simple, but can't narrow it down other then reac-bootstrap being the cause.
Did you require/import the Button component anywhere in your code? Maybe that's what was missing.
In my ignorance, I simply did not follow the universe:react-bootstrap documentation.
As a global
This package additionally export ReactBootstrap as a global, so you
can write inside any .jsx file:
let { Button } = ReactBootstrap;
<Button /> // React component
or
<ReactBootstrap.Button /> // React component
let { Button } = ReactBootstrap;
if (Meteor.isClient) {
Meteor.startup(function () {
let App=React.createClass({
render: function () {
return (
<div>
<Button>Default</Button>
</div>
);
}
});
React.render(<App/>, document.getElementById("container"));
});
}
I am using a decorator for some sliders like the following:
content = new Ractive({
el: '.wrapper',
template: templates.wrapper,
partials: templates,
data : { ... },
decorators: {
carousel: function( node )
{
console.log( 'carousel init' );
carousel = $( node ).owlCarousel({
items: 1,
navigation: false
});
return {
teardown: function () {
console.log( 'carousel destroy' );
carousel.trigger('destroy.owl.carousel').removeClass('owl-carousel owl-loaded');
carousel.find('.owl-stage-outer').children().unwrap();
}
}
}
}
}
What happens is that, as you can see in the logs, when swapping between a template which has inited the carousel to another template that has this decorator as well, the first decorator teardown is being triggered after the new template's decorator is initiated, therefore the carousel on the second template gets torn down and not the one in the first template.
Am I doing something wrong ? Thanks !
UPDATE
I have made a jsfiddle for it here : https://jsfiddle.net/05sq8o2k/6/
Make sure to tap load unsafe scripts if you get the warning because ractivejs cdn does not support https as far as I can see so jsfiddle kind of disagrees with it now.
This seems fixed in the next version of Ractive. Update your fiddle to use: https://cdn.ractivejs.org/edge/ractive.min.js
Kind regards
Bob
Lets stay I have a loginbutton.html file with template {{loginButton}}.
<template name="loginButton">
//rest of code
</template>
How could I render this in a react component. I've looked around and found a couple of answers but to be honest I need more guidance bc I'm fairly new to Meteor. Below is a link to a possible answer I found. I just don't know how to implement this or if this is what i'm actually looking for.
https://gist.github.com/emdagon/944472f39b58875045b6
I finally solved the issue. If you're trying to use a blaze template in a react component you have to make sure your meteor app is using "templating" on the client side (and in a package which is what I was using). Afterwards just follow the directions from the link above when creating your component passing the template in as a prop:
Base.components.photoButton = React.createClass({
componentDidMount: function() {
var componentRoot = React.findDOMNode(this);
var parentNode = componentRoot.parentNode;
parentNode.removeChild(componentRoot);
this.view = Blaze.render(this.props.template, parentNode);
},
componentWillUnmount: function() {
// Clean up Blaze view
Blaze.remove(this.view);
},
render: function() {
return (<div/>
)
},
}));
There is a nice atmosphere package blazetoreact.
It's very simple. If you have this Blaze template:
<template name="loginButton">
<!-- rest of code -->
</template>
Then you can use it as React component:
const LoginButton = BlazeToReact('loginButton');
class SomeComponent extends React.Component {
render() {
return (
<div>
<LoginButton />
</div>
);
}
}