How to save or cache a Component's html? - reactjs

I know you can store a Component state and alter it so that the element is "re rendered", however in my use case, there is a situation I have where the rendering is just not up to speed.
What im looking for is that once a Component has been rendered, I want its html code, including the html of its children.
Maybe something along the lines of:
render() {
return(
<ChildComponent/>
);
}
componentDidMount() {
// Get the html code of this Component here
// Something like:
// <div>
// <span>Child component</span>
// </div>
}
I've looked at this similar question:
React caching rendered components
But it doesn't go in depth on how one may obtain the html elements as a string

You either want to figure out a way to renderToString on the client or access the DOM directly, which returns the actual (not pretty) DOM node.
Here's an example using findDOMNode and outerHTML:
class Example extends React.Component {
componentDidMount() {
console.log(
ReactDOM.findDOMNode(this).outerHTML
);
}
render() {
return(
<div id="demo">
Ranch it up!
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById('View'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='View'></div>
I imagine this being not all that useful if you want to actually use this string somewhere (render it), so it's probably better to save store all the data (state) and go from there.

We ran into this same issue while working on our datagrid product http://www.reactdatagrid.com - We basically store the HTML tag as well as the attribute values in an object. Our render method looks something like this (not actual code):
render(){
this.reactElement = React.createElement(tagName, propertyBag, children);
return this.reactElement;
}
We have a fairly complex grid product and this works reasonably fast for us.

Related

React onTouchStart not firing

I am trying to implement a swipe feature in ReactJS, but before I even really dive in, I cannot seem to get the onTouchStart event listener to work. I have looked online but most answers are outdated, or do not address my question directly. This link is where I got the most information thus far, but it still falls short of my question and some of the answers are outdated. What's the proper way of binding touchstart on React JS?
I went down to creating the simplest form of the functionality and included that code below. I was trying to console.log when onTouchStart={this.swiped}> occurs. On a side note, if I change the listener to onClick onClick={this.swiped}>, this works immediately.
class App extends React.Component {
contructor() {
super();
this.swiped = this.swiped.bind(this);
}
swiped() {
console.log("Swiped")
}
render() {
return (
<div>
<div
className='swipe-card'
onTouchStart={this.swiped}>Swipe Me
</div>
</div>
)
}
}
Also, I have added the CSS style cursor: pointer to the element. I also tried adding
componentWillMount: function(){
React.initializeTouchEvents(true);
}
But according to the React blogs, React.initializeTouchEvents is no longer required.
This seems so trivial and something that should be really simple to implement. What am I missing? My goal is to implement this without an external library. Here is a link to Codepen where I was trying to implement this.
https://codepen.io/jorgeh84/pen/mMdBZg
This works for me. Maybe the issue is that you're not testing it on a real device?
class App extends React.Component {
contructor() {
super();
}
swiped = () => {
console.log("Swiped")
}
render() {
return (
<div>
<div className='swipe-card' onTouchStart={this.swiped}>Swipe Me</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('App'))
I realized that Daniel was onto something. So I do not need to be testing on an actual device, however, when using Chrome, you will need to use their device toolbar to simulate a mobile device for this to work.

Conditionally render list with Higher Order Component

My app has a feature toggle functionality that tells my UI whether or not a piece of UI should be rendered. I would like to create a Higher Order Component to conditionally render these types of components. In one scenario, I'm trying to conditionally render a list, but I'm running into this error:
ConditionalRender(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
This makes sense since I just am trying to render the children of this component. Here's what I've got so far:
https://jsfiddle.net/fmpeyton/cykmyabL/
var settings = { showHello: true, showGoodbye: false};
function ConditionalRender (props) {
var output = null;
if(props.shouldRender) output = props.children;
console.log(output);
// return (<li>{output}</li>); // This works, but isn't desired html structure
return ({output});
}
function App (props) {
return (
<ul>
<ConditionalRender shouldRender={props.settings.showHello}>
<li>Hello!</li>
</ConditionalRender>
<ConditionalRender shouldRender={props.settings.showGoodbye}>
<li>Goodbye...</li>
</ConditionalRender>
</ul>
);
}
ReactDOM.render(
<App settings={settings} />,
document.getElementById('container')
);
If I can help it, I would just like to render the children without any additional logic.This HOC would also handle more complex children down the line. Something like this:
<ConditionalRender shouldRender={props.settings.showHello}>
<div>
<p> blah blah blah</p>
<table>
<!-- ... -->
</table>
</div>
</ConditionalRender>
Any ideas?
Try this:
function App(props) {
return (
<ul>
{props.settings.showHello && <li>Hello!</li>}
{props.settings.showGoodbye && <li>Goodbye...</li>}
</ul>
);
}
P.S. Your code doesn't work because of this line:
return ({output});
Assuming you have es2015 support, it would be treated as object property shorthand. So it's the same as:
return {output: output};
which is not what React expects to get from the render method.
You could try this:
function ConditionalRender(props) {
if (props.shouldRender) {
// Make sure we have only a single child
return React.Children.only(props.children);
} else {
return null;
}
}
But this is not the simplest way. See more here.
P.P.S. Your ConditionalRender component is not what is called Higher-Order Component. According to the docs, HOC is a function that takes a component and returns a new component.

React Nested loops

I have some grouped data that I would like to render like such:
RowGroupTableHeader
RowGroup1
RowGroup1-row1
RowGroup1-row2
RowGroup2
RowGroup2-row1
RowGroup2-row2
RowGroup3-row3
Normally, I would do a loop through the groups, and within each loop, I would have an internal loop to go through each of the rows.
However, because I'm working with accessibility, div structures are very strict. eg. you cannot just throw in a surrounding container around div[role=rowgroup]. i.e. each rowgroup needs to be at the same level.
As such, I cannot use the usual Array.map() nested within each other because after the first iteration, I am expected to close the return() and cannot start a new Array.map().
Anyone got any ideas how I can achieve this?
Is there a wrapper component out there that can render its contents without the wrapper? eg. {content}?
Thanks.
John.
I'm not sure I completely understand the question. But your last sentence leads me to believe that you want to to write a React class that renders its child directly, without wrapping it in an outer element like div? If so, that is possible, but ONLY if you pass a SINGLE valid React component in as a child.
The following should work:
class Foo extends React.Component {
constructor(props){
super(props);
}
render() {
if(React.Children.count(this.props.children) === 1){
// If there is only one child, return it directly, unwrapped
return React.Children.only(this.props.children);
} else {
// Otherwise, return all children wrapped in div
return <div className="foo">{this.props.children}</div>
}
}
}
...
// Later on...
<Foo><div>Hello, world!</div></Foo>
// Would render simply as
// <div>
// Hello, world!
// </div>
<Foo><div>Bar</div><div>Baz</div></Foo>
// Would render as
// <div class="foo">
// <div>Bar</div>
// <div>Baz</div>
// </div>

Is passing components as props considered bad practice?

As the headline states: is something like the pseudo code below considered bad?
<Outer
a = { ComponentA }
b = { ComponentB }
/>
var Outer = (props) => {
var ComponentA = props.a;
var ComponentB = props.b;
// do fancy stuff
// ...
return (
<div>
<ComponentA { ...fancypropsForA } />
<ComponentB { ...fancypropsForB } />
</div>
);
}
As an example: I'm using it to display tree data in different ways by passing a component that will render the data of a single node.
EDIT
As requested, I will try to make my question a little more clear.
There is a component that has some logic and some markup that is the same every time you use this component. But there are two (or more) places in that markup that should be replacable.
Picture a calendar that displays a whole month. There is a component that renders an individual date, and one that renders the weekday (in the bar at the top).
You want to reuse that calendar in multiple places, but you need different markup for the date/weekday components each time.
One way to achieve this is:
<Calendar
data={ data }
weekdayComponent={ MyWeekDayComponent }
dateComponent={ MyDateComponent }
/>
<Calendar
data={ data }
weekdayComponent={ SomeOtherWeekDayComponent }
dateComponent={ SomeOtherDateComponent }
/>
So, i found that this works. But I'm not sure if that is actually bad.
As long as data flows only in one direction, you're generally OK. Your example is a little contrived, so it's hard to see what general problem you're trying to solve, but I think what you're actually looking for are Higher Order Components.
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e

React - how to do jQuery style find() to find children of a DOM node?

I've got a component that returns this:
return (
<div className="audio-widget">
<div
className={this.props.className}
onWheel={this.handleWheel}
/>
{controls}
</div>
)
I need to do the equivalent of:
handleWheel(event) {
let $canvas = $('.audio-widget').find('canvas');
[...]
}
The canvas is drawn programatically by a 3rd party script, so I can't just slap an ID on it (especially since this is a component and there are several per page).
Excuse the extreme n00b question, I'm brand new to React. Thanks!
This is a good use case for the ref prop. If you give a component a ref prop, e.g. ref="foo", upon rendering that component will be available as e.g. this.refs.foo. Then you can get the rendered DOM node with React.findDOMNode.
render() {
// ...
return (
<div ref="audioWidget" className="audio-widget">
<div
className={this.props.className}
onWheel={this.handleWheel}
/>
{controls}
</div>
);
}
handleWheel(event) {
let canvas = React.findDOMNode(this.refs.audioWidget)
.querySelector('canvas');
// ...
}
You can learn more about refs here: https://facebook.github.io/react/docs/more-about-refs.html
I think, it's a bad way to direct access 'canvas' with selector, the reason is as follows:
When you component changed, the React will do some diff works, then update your dom with a best way, that means, the node you get with selector may be changed to another node just for 'the best way'.
You can build a 'Child Component', and do something in the 'handleWheel' of the 'Parent Component', then communicate with the 'Child Component' through the 'props' for 'Child Component'

Resources