How to create inject React components from XML - javascript

Imagine you made a web framework that helps you quickly make blogs for clients. For the sake of this post, its the same blog template everytime, what changes is the content. You're React app is a simple structure of the following [where the Content state is just changing each time]
<App>
<Navigation/>
<Content/>
</App>
What makes the framework is you have XML files which contain the HTML. Each XML file represents one blog post. The app pulls all the HTML from the XML files, and puts it into the state of the App in a "blog posts" array. Depending on the state of the app, a specific entry in the array will be displayed in Content...
Content's state has a field called "html" which is what holds the HTML to be injected in string form. [you have to use dangerouslySetInnerHTML]
This concept works fine, and I have a version of it now. However, imagine you have a React components that you want to add to each blog post. Say you want to add the component into a specific blog post in a specific section. You want to add props to it and such. Now this goes out the window with dangerouslySetInnerHTML
This is where I am stuck trying to find the best direction to go. The only thought I have now is the following:
Since you would now be writing JSX in the XML, just make each blog post its own component. You would have ...etc and then if this.state.currentPost === 1 then display BlogPost1 and likewise. Yet you would have to have a huge block of if-statements depending on how many blogposts you have, and its not ideal to have to add everytime you have a new blogpost

When I read the title of your question I got curious and found this library to parse XML into React components: xml-to-react. But that's not what you are asking for.
As you want to use components in the middle of you string of HTML, I'll suggest: react-remarkable. This component compiles its children (a string with markdown/html/react) into react nodes.
Example from its docs:
var React = require('react');
var Markdown = require('react-remarkable');
var MyComponent = React.createClass({
render() {
return (
<div>
{/* Pass Markdown source to the `source` prop */}
<Markdown source="**Markdown is awesome!**" />
{/* Or pass it as children */}
{/* You can nest React components, too */}
<Markdown>{`
## Reasons React is great
1. Server-side rendering
2. This totally works:
<SomeOtherAmazingComponent />
Pretty neat!
`}</Markdown>
</div>
);
}
});

Related

How to create dynamic components

I see opportunities to minimize network bytes transfer of my website, but can't come up with a proper solution.
In Gatsby, I make use of .mdx files. In these files I can use React Components, such as:
<Cards id="id_1" />
There are dozens of cards defined in a .json file, which can be used across the website by just calling this component in de mdx file and passing their id.
The Cards component looks like somewhat like this:
import React from 'react'
import Img from 'gatsby-image';
import { StaticQuery, graphql } from 'gatsby';
const Cards = (props) => {
const card_id = props.id ? props.id.slice(0, 2) : [] // grab id
return <StaticQuery
query={graphql`
query Query {
images: allFile(filter: { sourceInstanceName: { eq: "card-images" } }) {
edges {
node {
childImageSharp {
fluid(maxHeight: 256, quality: 100) {
...GatsbyImageSharpFluid_withWebp
...GatsbyImageSharpFluidLimitPresentationSize
}
}
name
}
}
}
allCardsJson {
nodes {
name
id
}
}
}
`}
render={(data) => {
return(
// returns a component by filtering 'data' by 'card_id'
)
}}
/>
}
Everything works fine, but...
When this component is used, the full result of StaticQuery (meaning: all cards since filtering is done inside the return, not inside the staticquery) is send to visitors of the page. This is unnecessary and a waste of network bandwidth, because for example only one card (or a few) is used on the page.
I understand that a StaticQuery is .. static. Thus, I cannot dynamically filter within this query to limit the size of the result.
DynamicQuerys are used when building pages, not inside components.
Is it possible to somehow create components with dynamic content (defined elsewhere), but limited to just the required data? (like by providing an id like I've tried)
I am thinking about creating a seperate file for each Card. Then import the Cards needed into the mdx file and passing it to the component. Thoughts?
There is no documentation about my use case. This makes me wonder if I'm using it as intended.
I solved it by adding the used data to the page context by editing the gatsby-node.js:
Get the mdxAST of the post, filter the components, then filter the ids used.
Add this list of ids to the page context.
Move the query stated in the question above to the post GraphQL query. Use the list of ids provided by page context to filter the data down to only the used ids in this post.
Pass this data as a property to the MDXRenderer.
Pass this data in the .mdx file to the cards component, such as: <Cards data={props.cards_data} />.
Now the compontent received the data without using a StaticQuery.
This works, but it feels kinda weird. There must be a better, more clean, solution in my opinion.
GraphQL queries are run ONCE when you run gatsby develop or gatsby build. This is a counterintuitive way how Gatsby works but read it yourself:
Gatsby uses GraphQL at build-time and not for live sites.
More information about the gatsby build process and how GraphQL factors into it.
This means you already built your component the way you are supposed to. During build all your cards are queried and kept in memory. When creating the HTML for your pages with your cards, only the cards with your ID are used to build your page. Thus the user only sees gets transmitted the pages with filtered IDs.
You can double check if really only the cards with the ID are inside your page:
run gatsby clean: make sure old fragments of your page are removed
run gatsby build: Create your site from scratch
Check your public folder in your project root. This is the classic webpage that gatsby builds. Navigate to your pages with your cards for example /public/blog/example-page-with-card. Take a look inside the HTML of the page: Does it contain all the cards or just the one with the IDs you need?

Can I give arguments to a react-app? (dependency injection with React)

I would like to use a React-App, and give it some arguments (props), depending on where I embed it.
So one step back, we are using React actually as a library, and not the entire page is in React. We have a very functioning website, and some parts are now being build in react. Our motivation is: If you want the same component in another page, you can simply copy-paste 3 lines which include the css and js files, put a <div id="myReactAppRoot"></div>, and that's it. Very quick, very clean, and instantly functioning.
My question
When I have another "copy" of the React app, I would like to give it a different starting state.
One example use-case: I have two pages, in one I want the data to be grouped by X and in the other grouped by Y.
Another use-case, which I will have on my next project: disable editng, depending on the users permission level (the permission level is known by the main page).
How can I achive this?
My current solution
My current solution is simply having a utils.js in the React app, which I use to access the windows object and get out the pieces I want:
const utils = {
fun1: window.myProject.forReact,fun1,
groupElements: window.myProject.forReact.groupElements,
permissionLevel: window.myProject.forReact.permissionLevel
};
export default utils;
Then importing utils in other components and using the functions/reading the values. And of course making those objects available on the main page.
But really, this feels wrong.
My ideal solution would look a lot like the Vue.js way:
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
Because I can just copy paste this bit, and change the Hello Vue!, and all the sudden the starting state is different in my "second copy" of it. Or even more cleverly, wrap it in a function that gets some initialState and put that JavaScript part in a file which I reference.
I have considered
I have considered editing the compiled JavaScript code that is being referenced. So far I only saw that the actual hooking into the myReactAppRoot-element is being done in the main.chunck.js, and editing that file seems too much like a hack (feels more wrong than my current solution).
To expand on Mike's comment, let's first translate your Vue app into React:
//html
<div id="root"></div>
//JS
const App = ({message}) => <div>{message}</div>
const rootElement = document.getElementById("root");
ReactDOM.render(
<App message={"Hello, React!"}/>
rootElement
);
A function that mounts an instance of App on a DOM node with id domId would be something like
function mountAppWithMessageOnNode(message, domId){
const rootElement = document.getElementById(domId);
ReactDOM.render(
<App message={message}/>
rootElement
);
}

Vue.js - component inside component

I do have my component called Grid. Inside this component I load JSON data from server and i render them. They are mostly string and integers. Sometimes the JSON contains HTML like <strong>myvalue</stong> so I render the data with three brackets {{{ and }}}.
The thing is when the HTML is not pure HTML but component like <my-component my-param="1"></my-component>. How to tell to Vue.js to render this coponent? All I get is the HTML purely printed into grid.
Thanks
You need to compile again that piece of code you've loaded from remote.
ps: I will use jQuery to manipulate the DOM.
Inside this component I load JSON data from server and i render them.
I'll assume you have a function named "loadAndRenderFromServer()", please adapt the code below to fits you.
Eg: If your grid has the markup <div id='grid'>
// vuecomponent.js
export default {
[...]
methods: {
loadAndRenderFromServer() {
// first, load remote content and insert into #grid
// now, compile
this.$compile($("#grid").get(0));
}
},
[...]
}
You may need to use "decompile" if your component starts to duplicate the loaded content. Check into VueJS docs for compile and decompile methods.
Using v-html (which is equivalent to {{{}}}) will not render what's inside it if it's a component.
Instead try to use <slot> in your parent template.
Otherwise, if you want dynamic components you need to use <component> and if you want content inside those dynamic component you need to use <slot>s.
I would suggest you to use something like
<component :is="myComponent" />
and inside the models of those components put some <slot>s to insert arbitrary content.

Render function in reactjs

Quick question. I'm learning react js.
When we create a component, we provide in the render function the html template of the component to render.
So far I have only seen small components with very small pieces of html, but I was just wondering what happen if we have a component with a huge html template, is there any way to provide the path to a separate html file? Or we are forced to write all the html directly inside the render function? Thanks!
You should always write it in the render function. You're not writing HTML in there, you're writing JSX, which is compiled into Javascript. Something like <div className="test"> is converted into React.createElement("div", {className: 'test'});.
You shouldn't have an issue of size as long as you break down large components into a composition of many smaller components. You can include other components by including them in your render function, like this: <SomeComponent someProp="someVal" />.
You can split your render function to the bunch of good-named methods like a partials in old plain html-templates. It's useful to make complex react-components, because you will remove big unreadable html-part from your code.
For example, here is some pseudo-code described this approach:
class NavBar extends React.Component {
// Render user name and links on profile and logout
renderUser() {
if (!user) return;
return <div>{user.name}</div>;
}
// Render list with nav-bar items if they exists
renderNavBarItems() {
if (!user) return;
return <ul>{this.items.map((i) <li><a href={i.link}>{i.name}</a></li>)}</ul>;
}
render() {
return (<div className="nav-bar">
{this.renderNavBarItems()}
{this.renderUser()}
</div>);
}
}

What are the difference/similarities between React (app framework from Facebook) and react.js (reactive extensions for JS)?

I recently learned about Facebook/Instagram's app framework for JavaScript called "React" and wanted to look more into it. However, I found myself getting conflicting search results, as there is another library of a similar name. So, my question is this: Are there similarities between the two, or could someone do a better job at naming?
React
http://facebook.github.io/react/index.html
react.js
http://www.reactjs.com/
react.js is a language extension that lets you have automatic binding for values. The name React comes from the automatic updates of the values when one changes.
react( "soonChanged = undefined" );
react( "reactive = soonChanged + 5" );
react( "reactive2 = reactive * 10" );
react( "soonChanged = 10" );
// Changes the value of reactive from "undefined5" to 15
// and of reactive2 from NaN to 150
React on the other end is a framework to build user interfaces. The name React comes from the automatic update of the UI when some state changes.
/** #jsx React.DOM */
var converter = new Showdown.converter();
var MarkdownEditor = React.createClass({
getInitialState: function() {
return {value: 'Type some *markdown* here!'};
},
handleChange: function() {
this.setState({value: this.refs.textarea.getDOMNode().value});
},
render: function() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
ref="textarea"
defaultValue={this.state.value} />
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={{
__html: converter.makeHtml(this.state.value)
}}
/>
</div>
);
}
});
React.renderComponent(<MarkdownEditor />, mountNode);
A bit more comparison added to above:
react.js
can also do auto UI updating, but you need to manually code that:
/* **syntax aren't correct but the idea eg:
(you can find it in their doc for correct syntax) */
react( "yourReactiveComponent = 1" )
react( "$('body').html( yourReactiveComponent )")
/* now u change that variable */
react( "yourReactiveComponent = 4" )
/* it will automatically call that jquery function to change the html from 1 to 4 */
it is not really a framework, just an PUBSUB event helper, that subscribe and publish on variable change
awesome for small applications
facebook React
this is a framework
they will deal with a lot of cross browser issues
they have stuff worked on optimising performance such as an virtual DOM
has their own cool markup syntax compiler JSX and JSXtransformer, so you can write declarative HTML in a JS file and than transform it into a real JS file
they are component focus, so you will have both js and html that related to one component managed within their own code block, making it so much easier to change DOM stuff without switching all the time from JS to TPL and vice versa, This is the part where i love the most, I've been coding like this for some time, but never have a framework that does this for me, now I do :)
now http://www.reactjs.com/ redirect to https://facebook.github.io/react/
It's domain seems to be acquired!
at this time 2016-08-23, the google search result of react.js are all about facebook react
i don't know what you said react.js is, it seems disappeared!
from the answer above
react.js is a language extension
i just think it seems that the old react.js is now http://reactivex.io/, i don't know right or wrong
you can see some comparison here: http://blog.getsetbro.com/js/FB-react-vs-reactiveJS-vs-ractiveJS-vs-reactiveUI-vs-reactiveX.html

Categories