Send React component's HTML to server - javascript

So I have a react component, <ReviewScreen />. It takes in some props, styles them, and presents them. I need to convert this component into HTML, and send it to my backend so that I can generate a PDF on my server.
I tried:
import { renderToStaticMarkup } from 'react-dom/server';
import ReviewScreen from '../somePath';
const html = renderToStaticMarkup(ReviewScreen)
// ... send the html variable to backend using some HTTP library
Problem: the html variable is always empty. My question is: a) is this a 'good' way of doing what I'm trying to achieve? b) is there a better method?
UPDATE: Changing to <ReviewScreen /> actually gets a response. However, I forgot to mention that this component also talks to my Redux store which results in an Invariant Violation: Could not find “store” error.

renderToStaticMarkup takes in an element, not the component type - you'd need to do this:
const html = renderToStaticMarkup(<ReviewScreen />)
Or, without JSX:
const html = renderToStaticMarkup(React.createElement(ReviewScreen))
That said, I think you would be better off generating the HTML on the server instead - rendering arbitary markup sent from the client seems like it could get messy.

You should be doing this:
const html = renderToStaticMarkup(<ReviewScreen />)
Not:
const html = renderToStaticMarkup(ReviewScreen)

Related

Will JSX conditional rendering out of an object code split?

Will conditional rendering out of an object code split and lazy load as expected? Here's a short example of what I'm talking about.
const Component1 = lazy(() => import('some path'));
const Component2 = lazy(() => import('some path'));
const Component3 = lazy(() => import('some path'));
render () {
const { selectionIndex } = this.state;
<Suspense fallback={<div>Loading...</div>}>
{{
one: <Component1 />,
two: <Component2 />,
three: <Component3 />,
}[selectionIndex]}
</Suspense>
}
I want to know whether all three components will load on render, or just the one selected by selectionIndex. I'm trying to use this to conditionally select something to display based on a menu set by state, but I don't want to load everything at once.
They will not get rendered all at once. You can experiment by yourself, put console.log inside components is an easy way to find out.
React for web consists of two libs, "react" and "react-dom". "react" is in charge of encapsulating your logic intention into declarative data structures, while "react-dom" consumes these data structures and handles the actual "rendering" part of job.
The JSX element creation syntax <Component {…props} /> translates to plain JS as an API call to React.createElement(Component, props). The return value of this API call is actually just a plain object of certain shape that roughly looks like:
{
type: Component,
props: props
}
This is the aforementioned "declarative data structure". You can inspect it in console.
As you can see, calling React.createElement just return such data structure, it will not directly call the .render() method or functional component’s function body. The data structure is submitted to "react-dom" lib to be eventually "rendered".
So your example code just create those data structures, but the related component will not be rendered.
seems like its conditionally loaded based on selectionIndex. all the other components are not loaded at once.
P.S.: if you ever feel like which will get load first, just put a console log in that component and debug easily
conditionally load demo link - if you open this, the components are being loaded initially based on selectionIndex value being "one".
I'm not going to go into too much technical detail, because I feel like #hackape already provided you with a great answer as to why, point of my answer is just to explain how (to check it)
In general, I'd recommend you to download download the React Developer Tools
chrome link
firefox link
and then you can check which components are being rendered if you open the components tab inside your developer console. Here's a sandboxed example, best way to find out is to test it yourself afterall :-)
As you can see in the developer tools (bottom right), only the currently set element is being rendered

Expected server HTML to contain a matching <tag> in <tag>

We are using nextjs and getting this error at page refresh (or first load)
My error is:
react-dom.development.js:88 Warning: Expected server HTML to contain a matching <tag> in <tag>.
The code of our functional component looks like this:
export default MyComponent () {
if(! props.something){ // ← this is causing the problem.
return null;
}
return (
<>
HTML here ...
</>
)
}
From my understanding, SSR is different from client side rendering and this is why react is complaining.
The app is working fine but this error is showing in the console and we don't want to have many errors being thrown there as this may prevent us from seeing the real errors when they happens.
Solution:
The solution is to use dynamic imports and and wrap the component call into:
const MyDynamicComponent = dynamic(() => import('./myComponent'), {ssr: false});
//use it:
<MyDynamicComponent />
//OR :
const MyDynamicComponent = dynamic(() => import('./myComponent'))
//use it:
{typeof window !== 'undefined' && (
<MyDynamicComponent />
)}
May be importing your component dynamically should solve this.
Below is the link you can refer;
https://nextjs.org/docs/advanced-features/dynamic-import
I've been looking for solution of a similar problem, but I was using react-window lib and the problem appeared to be in it. I passed different height to it, depends on whether it's loading on server or client, so it gave me back different elements.
My solution was to pass the same height at the beginning, but to change it to window.innerHeight on useEffect ( = on client load).
When this happened to me on a Next project, I had not nested my html table elements properly. Specifically, didn't wrap my <tr> in a <tbody>
the code is executed first on the server after in the browser in my case this is why i get this error and other error with style component like :
Warning: Prop className did not match. Server: "CardUserInfo....
so this link help :
https://github.com/vercel/next.js/discussions/17443
enter link description here
and the solution for me like montienned in this disscussion implement useState useEffect
const [mount, setMount] = useState(false)
useEffect(() => {
setMount(true)
}, [ ])
return mount&&(
<InfoUserCard/>)
In my case the console error displaying Warning: Expected server HTML to contain a matching <sup> in <span>. using Safari Web Browser in development ONLY, i.e. localhost:3000 . Just get rid of this boring error by using Chrome Web Browser.
This boring error will not be exist in production with Safari Web Browser.

Populate 3rd party element from Redux with JSON instead of innerHTML or attributes

I am using a 3rd party library to generate a sortable grid that expects to be fed JSON data, is there a way to send part of the redux store to this non-react grid other than as a react component, attribute or innerHtml since it does expect JSON? The challenges are that all my redux scripts are modules which is a scoping issue since, in this case, the 3rd party element is wrapped in asp.net so I can't expose it to a function (though it can call a javascript function to get the data), and that I need to be able to subscribe to changes, this has proven unnecessarily difficult so far.
You can just call store.getState() to get the current state of the store.
You may want to attach the store on to the window to give it global scope when you create it,
window.redux = { store }
or if using modern js, create a wrapper export function in the file that you create it
export const getStore = () => store
So that you can then do
getStore().getState()
If I understand your question correctly, you are using some third-party element in a react app that takes data in the form of JSON? Without more details on the third-party library its hard to give a proper answer but I'll give it a shot.
Whatever this library is, you have to render it somehow at some point. Since we don't know what you are using I am going to pick jQuery.
Assume the following usage
$("#grid").initializeGrid(data);
You can expect the react component to be something like
const GridWrapper = (props) => {
const tableData = useSelector(selectTableJson);
useEffect(() => {
$("#grid").initializeGrid(data);
}, [tableData]);
return (
<div id="grid" />
);
}
Basically what is happening is you select the data from the redux store, and then initialize the third party component with that data.

Can't read react state inside JSX in stack with NEXTJS

I'm having an issue with reading the state. Slider component nested inside [projects.js]. Since NextJS has a very convenient method for dynamic routings the main idea is to change most of the data inside a template component based on the current pathname.
The expected behavior for my code was to generate working path for images (look 'key' and 'src').
<motion.img
ref={imageRef}
className='absolute h-full md:rounded object-contain'
key={images[src][imageIndex]}
src={images[src][imageIndex]}
There're a couple of ways to do it:
Ask Next about the rout while client-side rendering and store it in the state.
import { useRouter } from 'next/router';
const router = useRouter();
useEffect(() => {
setSrc(router.query.project);
}, [src]);
Use getInitialProps and store data there as first function fires on the server.
Carousel.getInitialProps = async query => {
return {
src: images[query.project]
};
};
Preferably I would use the second option with initial props, but I can't with next JS. Functional of the slider doesn't allow to makу it because the code breaks when returning back to the previous page. NextJs just makes [projects.js] statically available on the client-side by default and restricts initial props.
So, when I'm using state it works fine, I can read from it in console.log
console.log(src); ==== 'barva'
// console.log(images.barva[0]); ====== ["/images/barva/barva-design.png", ...]
// console.log(images[src][imageIndex]); Cannot read property '0' of undefined
Very strange behaivor since it reads my import with json file, it reads when assigned to the state, it shows pictures when I fill out path manualy without any dynamic variables, it even reads second part of the path [imageIndex] but it never reads state as [src] inside JSX.
Are there any better practices of how to import data to make component dynamic?
or How to fix this code??
repo to the project:
gihub repo

Draft.js and stateToHTML, how to render output html in react component?

I've got my Draft js editor working fine, it saves to my database, using convertToRaw(editorState1.getCurrentContent()), and I am getting it back and converting it to HTML using draft-js-export-html and stateToHTML(convertFromRaw(dbContent.content.text01)).
So far so good... but now I have raw HTML that I want to display in my react component, and here comes the trouble.
Just rendering it with {props.text01} outputs it as a string and turns into <p>adfasfadfs</p> as text.
Obviously I want it to render as HTML. How do I do that?
I have looked at dangerouslySetInnerHTML but I would prefer not having ANOTHER plugin just to get my Draft js working the way I want it to.
Am I going at it the wrong way, or is dangerouslySetInnerHTML the only way to do it?
As described in this answer, React will escape HTML by default (that's why it's just rendered as a string). But you can force the rendering by using the dangerouslySetInnerHTML property. You'd just have to take potential XSS attacks into consideration.
If Draft is already installed, another way to just simply render the content is to use the readOnly prop on the DraftEditor.
you can use this npm module.
link is link
npm install --save html-to-react
Examples
Simple
The following example parses each node and its attributes and returns a tree of React elements.
var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;
var htmlInput = '<div><h1>Title</h1><p>A paragraph</p></div>';
var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);
assert.equal(reactHtml, htmlInput); // true

Categories

Resources