I have a form (example snippet below) that simply outputs state on submit.
This is as expected but now I want to save the rendered output to a file (.html) - How can I achieve this? I am assuming it would involve node but not sure since I am pretty new to React.
Edit: The question has mostly been answered, I am updating the code snippet to highlight a new issue that I am having. - I am trying to output a full HTML string using the renderToStaticMarkup method, however, the method is converting characters (',<,>,&) to (" < > &) on output.
В идеале я хотел бы, чтобы отображаемый файл был действительным рабочим файлом HTML, который можно открыть в браузере. В настоящее время токовый выход не работает из-за проблемы преобразования символов.
У меня такое ощущение, что может быть способ избежать кодировки символов, однако, поскольку я новичок в реакции, я не совсем уверен в рабочем решении.
Thank you in advance for any help on this.
<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="true">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>
function Result(props) {
const { image, title, bodyText, btnText, btnUrl, btnColor } = props;
return <>{`<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> ${title} </title>
<!--[if !mso]><!-- -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body {
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table,
td {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
</style>
<!--[if !mso]><!-->
<style type="text/css">
@media only screen and (min-width:480px) {
.mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
.mj-column-px-600 {
width: 600px !important;
max-width: 600px;
}
}
</style>
<style type="text/css">
@media only screen and (max-width: 480px) {
.small p {
font-size: 9px !important;
}
}
</style>
</head>
<body>
<div style="">
<table class="body" cellpadding="0" align="center" cellspacing="0">
<tr>
<td align="center" style="text-align:center; padding:0px 0px 0px 0px;">
<font style="display: none; max-height: 0px; overflow: hidden;"> ‌ ‌ ‌</font>
</td>
</tr>
</table>
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:5px 0 5px 0;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:200px;"> <img alt="Company Name" height="auto" src="" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;"
width="200"> </td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0px;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody>
<tr>
<td style="vertical-align:top;padding:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:0px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
<tbody>
<tr>
<td style="width:600px;"> <img alt="" height="auto" src="http://image.e.campingworldrv.com/lib/fe9915737d640c7f75/m/1/648eb085-3d86-4be1-a8e7-f3d8f8023c53.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;"
width="600"> </td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:5px 10px 5px 10px;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:580px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<div style="font-family:Arial, Helvetica, sans-serif;;font-size:13px;line-height:1;text-align:center;color:#000000;"> <span style="color: #000000; font-weight: bold; font-size:24px">${age} ${bodyText}</span><br><br><span style="font-size: 14px; color: #000000;">${bodyText}</span> </div>
</td>
</tr>
<tr>
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
<tr>
<td align="center" bgcolor="#000000" role="presentation" style="border:none;border-radius:0px;cursor:auto;padding:10px 25px;background:#000000;" valign="middle"> <a href="#" style="background:#000000;color:#ffffff;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;font-weight:bold;line-height:120%;Margin:0;text-decoration:none;text-transform:none;" target="_blank">
${btnText}
</a> </td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:5px 0px 5px 0px;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody>
<tr>
<td style="vertical-align:top;padding:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
<tr>
<td style="font-size:0px;padding:0px;word-break:break-word;">
<p style="border-top:solid 1px #6a6a6a;font-size:1;margin:0px auto;width:100%;"> </p>
<!--[if mso | IE]>
<table
align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 1px #6a6a6a;font-size:1;margin:0px auto;width:600px;" role="presentation" width="600px"
>
<tr>
<td style="height:0;line-height:0;">
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#ffffff;background-color:#ffffff;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
<tbody>
<tr>
<td style="direction:ltr;font-size:0px;padding:0px 10px 20px 10px;text-align:center;vertical-align:top;">
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td
class="" style="vertical-align:top;width:580px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody>
<tr>
<td style="vertical-align:top;padding:0px;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
<tr>
<td align="center" style="font-size:0px;padding:0px;word-break:break-word;">
<div style="font-family:Arial, Helvetica, sans-serif;;font-size:10px;line-height:1;text-align:center;color:#6a6a6a;"> Don't want anymore emails from us? <a href="http://www.unsubscribe.com/">Unsubscribe</a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</tbody>
</table>
</div>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</div>
</body>
</html>`}</>;
}
function download(filename, text) {
let element = document.createElement('a');
element.setAttribute(
'href',
'data:text/plain;charset=utf-8,' + encodeURIComponent(text)
);
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function BasicHtml(props) {
const { title, children } = props;
return (
<html>
<head>
<title>{title}</title>
</head>
<body>{children}</body>
</html>
);
}
export default class FormComponent extends React.Component {
state = { name: '', age: null, submitted: false };
handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.setState({ submitted: true });
this.generateHtmlFile();
};
generateHtmlFile = () => {
const { name, age } = this.state;
const formHtml = ReactDomServer.renderToStaticMarkup(
<BasicHtml title={name}>
<FormComponent />
</BasicHtml>
);
const resultHtml = ReactDomServer.renderToStaticMarkup(
<BasicHtml title={name}>
<Result name={name} age={age} />
</BasicHtml>
);
download('result.html', resultHtml);
download('form.html', formHtml);
};
render() {
const { name, age, submitted } = this.state;
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Name:{' '}
<input
name="name"
type="text"
value={this.state.name}
onChange={this.handleChange}
required
/>
</label>
<br />
<br />
<label>
Age:{' '}
<input
name="age"
type="number"
value={this.state.age}
onChange={this.handleChange}
required
/>
</label>
<br />
<br />
<input type="submit" value="Submit" />
</form>
<br />
{submitted ? <Result name={name} age={age} /> : null}
</div>
);
}
}
ReactDOM.render(<FormComponent />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>