Using React with uncontrolled third-party components - javascript

I'd like to create a UI similar to JSFiddle using React:
A panel for HTML, CSS and JS
A preview panel
A single "Run" button that updates the preview
I'd like to use Microsoft's Monaco editor for the HTML, CSS and JS panels to get syntax highlight and autocomplete.
I've abstracted out a generic MonacoEditor component. My component hierarchy looks something like this:
<Root>
<div>HTML <MonacoEditor /></div>
<div>CSS <MonacoEditor /></div>
<div>JS <MonacoEditor /></div>
<button onClick={this.run}>Run</button>
<PreviewPanel />
</Root>
If I were implementing this UI in Vanilla JS, the run() method would call getValue() on each Monaco instance to extract the full text from each panel and generate the preview.
This becomes awkward with React, however, since the run() method can't call methods on instances of child components.
One workaround would be for the MonacoEditor to have an onUpdate prop which gets fired on every keystroke. The Root component could store the provisional contents of each panel for when the "Run" button was clicked. This is what I might do if each editor were a <textarea>. But it's a non-starter with Monaco. Serializing the text of the editor on every keystroke makes it unusably slow.
The only other approach I can think of is passing in a "getter setter" to the MonacoEditor component, e.g.:
class Root extends React.Component {
render() {
return (
<div>
<MonacoEditor setGetter={getter => this.getHTML=getter} />
<MonacoEditor setGetter={getter => this.getCSS=getter} />
<MonacoEditor setGetter={getter => this.getJS=getter} />
<button onClick={() => this.run()}>Run</button>
<PreviewPanel />
</div>
);
}
run() {
const html = this.getHTML();
const css = this.getCSS();
const js = this.getJS();
// ...
}
}
But this feels extremely awkward and counter to the idea of one-way databinding. Is there a better, more idiomatic approach?

You can checkout react-monaco-editor.
This will satisfy all your requirements! Especially getting value from the editor instance.
If not this, declare a function inside the editor component and use ref to call that function from other components.
Hope it helps!

Related

What is the different between react component and function as component in react

I'm very confused learning react.
For example I have very simple react component
export default function Foo(){
return(
<div>
<div>some text</div>
</div>
)
}
And I want to add a child component:
export default function Foo(){
const Bar = ()=>{
return (
<input placeholder="some input"/>
)
}
return(
<div>
<div>some text</div>
</div>
)
}
And as much as I know, I can use this component in two ways:
1. Use as function
return(
<div>
<div>some text</div>
{Bar()}
</div>
)
2. use as component:
return(
<div>
<div>some text</div>
<Bar/>
</div>
)
What exactly different between these two? I thought it was same, until I faced an issue with input field, that if I use component as <Bar/>, The focus on input field will be lost after I enter first letter
Demo here: https://codesandbox.io/s/gifted-archimedes-l7bce7?file=/src/App.js
So what is the exact problem here? I code as component all the time, as per my understand <Bar/> is same as Bar() when it return react component
Am I right or not?
Edit: I found this blog, and it very close to this question and it great too :)
https://dev.to/igor_bykov/react-calling-functional-components-as-functions-1d3l?signin=true
To be a component, function returning JSX should be used as <Component /> and not as Component().
When a functional component is used as <Component /> it will have a lifecycle and can have a state.
When a function is called directly as Component() it will just run and (probably) return something. No lifecycle, no hooks, none of the React magic.
The above 3 statement is the answer to your probem.
When you call the component as {Child()}, it does not have any lifecycle or hook and when you call as , it has it's own lifecycle and hooks this is why you are facing those problems.
For more read on this topis: Link.
I have seen your codesand box demo,
form there I think that the reason for losing focus from input field is the place where you have used useState.
Your can do two things here that's:
Either
Pass the state as props from parent to child component.
Or
use useState inside your child component as the parent does not require the state value I prefer the second way.
You can Read this for more knowledge of where to put the useState and when do you really need to use useState.
When you create a new component you can re-use that in another functional component.Whereas, If you create function then you cannot re-use in another functional component, it will have limited access to that particular functional component only.

Is there a way to show a React Component code into a <code> tag?

I'm building a tester page where the user sees a library component and documents its use.
Here is the component:
render = () => {
let component = (
<Slider
onSlide={this.handleSlide}
totalCount={120}
/>
);
return (
<div>
<h2>Slider Test:</h2>
{component}
<code>HOW TO PRINT COMPONENT CODE HERE?</code>
</div>
);
};
I want to show the component in use and at the end the code I've used to test it.
How can I put on screen the component code without the need to replicate it inside the tag?
Is there a way to do it directly or though an existing npm library?
You could escape the code and it should appear correctly.
You can use that library to do it escape-html npm
You should also be able to find specialized libraries to do it like this one react code view npm

Mixing React Components with HTML Blocks

Something that's always confused me is how many React examples show everything as components. But's let's say I only need to include some simple HTML alongside my components, like:
class Homepage extends Component {
render() {
return (
<Container>
<Hero />
<Features />
<div className="copyright">Copyright Some Company Name.</div>
</Container>
);
}
}
The div element will never be more than static text.
Should the <div> be moved into a pure component? Or is it ok to simplify the Homepage component by adding plain HTML this?
Sure it's ok. all in all it's HTML in the end. React components are set of html elements when you call the render function.
One rule of thumb i follow is: create a new component when you think a new responsibility is in order.
That div is a component just like any other, except it is a "primitive" one. There should be no problem mixing the primitive components from HTML with your own custom components.

React should form elements be a separate component?

I keep reading that when in doubt I should turn an element into a component. So are there actually any benefits to turning form elements such as <input /> to components.
Consider the following:
const SomeComp = (props) => {
return (
<form className='someClass' onSubmit={props.handleSubmit}>
<Input
className='someClass'
type='text'
id='someId'
placeholder='Enter Something'
onChange={props.handleChange}
value={props.side}
/>
</form>
)
}
Unless I'm using options like autoCorrect, autoCapitalize, spellCheck the only things I'll save by wrapping the input into a component like <TextInput/> and importing it to various forms is not adding the type prop to each input and maybe the fact that the error for the input is not declared at the top of the form.
Is there anything else I'm missing? What's the most beneficial way to approch such form elements and why?
Usually you will not want to turn very simple elements like inputs into separate components, unless you are expecting some special functionality from them.
The simplest way to go through is to always have, for each functional need (like a login page for example), a smart component for handling the behavior and functionality, and one dumb components for displaying the ui elements.
When you start feeling there is too much code in some of your smart components, or a dumb component has gone to large you can start dividing them. Otherwise try to keep it simple.
I use styled-components and do stuff like this all the time. The basic idea with Styled Components is that you attached CSS styles to your component instead of creating CSS classes to target, for example, all input elements or using inline styles which limit what you can do (i.e. media queries, psuedo-selectors, etc). And it allows you to separate your components functionality from it's presentation (within the same file).
Here is a link to a youtube video on the topic: https://www.youtube.com/watch?v=jaqDA7Btm3c
This way, you avoid the need for a global CSS file that is hard to maintain and doesn't exactly fit well within the webpack ecosystem that views your assets as a graph of dependencies.
If you are not interested in styled-components, and are happy with the way you style your form elements, then I see no reason to create a custom Input component.
For example, in Facebook's docs on React forms, they do not create custom form components.
https://facebook.github.io/react/docs/forms.html
Unrelated:
If you don't already know, you can write your example like so:
const SomeComp = props =>
<form className='someClass' onSubmit={props.handleSubmit}>
<Input
className='someClass'
type='text'
id='someId'
placeholder='Enter Something'
onChange={props.handleChange}
value={props.side}
/>
</form>
(removed the () around the single argument, and removed the {} and return statement. Like I said, unrelated, but thought I would mention it in case you were not aware.

Configure js-beautify within a react component

I am using js-beautify (the html-beautify option) to format html that is being displayed on my page, it displays but it's collapsing all the html to 1 line which is obviously not ideal because it's a pain to read. It is basically trying to format HTML as Javascript because the actual html beautify is not being applied.
I'm using it in react as below inside a specific component file for that item does anyone know how to fix this?
import htmlBeautify from 'js-beautify'
const htmlString = htmlBeautify(renderToStaticMarkup(<Component />))
export default () =>
<Example staticMarkup={htmlString}>
<Component />
</Example>
Update:
<Example/> is another component that renders out a bunch of additional stuff like a markdown description.
I'm using https://github.com/alexlande/react-style-guide to create a styleguide and passing the static html markup to staticMarkup prop to display rather than just showing the react component which in this context isn't particulary useful.

Categories