Conditionally render list with Higher Order Component - reactjs

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.

Related

integrate a third party component

I'm using react-infinity as an example here. (Link to react-infinity's Readme)
After doing var Infinity = require('react-infinity'), you have access to an Infinity variable with various props.
(I presume Infinity is going to be used inside some component I create, e.g. myComponent)
This is where I am stumped. How am I supposed to use this Infinity variable?
you would use it as just another JSX component as follows...
//.....
render() {
return (
<div>
<Infinity {...props} />
</div>
);
}
//.....
where props are whatever properties the thirdparty component specs.

How to save or cache a Component's html?

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.

Passing children from XHP to ReactJS

I have an XHP component:
final class :common:message-stripe extends :ui:base {
use XHPReact;
protected function compose() {
$this->constructReactInstance( "MessageStripe", Map {} );
return <div id={$this->getID()} />;
}
}
that should look like this in my .php file:
<common:messagestripe>
This is my message :)
</common:messagestripe>
On the ReactJS side, the component looks something like this:
var MessageStripe = React.createClass({
render: function() {
return (
<div className="message"> {this.props.children} </div>
);
}
});
However, I get errors about rendering null in my ReactJS component, which means that children are not sent correctly. So, my question: how can I pass the children from XHP to ReactJS?
You're not including your children when rendering your XHP component.
final class :common:message-stripe extends :ui:base {
use XHPReact;
protected function compose() {
$this->constructReactInstance( "MessageStripe", Map {} );
return <div>{$this->getChildren()}</div>;
}
}
Additionally, (assuming you built your :ui:base element with attribute forwarding as outlined here: Building a Good UI Framework with XHP) you don't need to manually set the ID of your root element, XHPJS::element() will do that for you.

how to append new component in reactjs not being bundled

I am new to ReactJS and had been through some examples: flux-todo-mvc.
Since react keeps component in a tree structure and updates on state change.
How can I add a new child component (not bundled) at specific node of tree without page refresh?
More Description
Suppose component X can have three types of child: A, B and C. At first GET request it is always A so X -> A is rendered and to make it fast we did not include B and C. For example:
X = React.createClass({
render: function() {
return (
<A />
);
}
});
React.render( <X />, document.getElementById('_x') );
After this, with some change in state can we change child of X to B or C using AJAX request
You can write conditional logic inside your render function to set a variable to null or a component instance. And inject that inside the returned render JSX.
Such as:
render: function() {
var subComponent = null;
if (this.state.showSub) {
subComponent = <Child />;
}
return (
<div>{subComponent}</div>
);
}
Only way to do it with state changes in real time. Can't update the render code in real time without an actual refresh.
you can do something like this:
render: function() {
var child = function(){
if(this.state.ajax_result ==1) {return <B/>
else if(this.state.ajax_result ==2) {return <C/>}
else {return <A/>}
}
return ( {child} );
}
now outside of render, listen to your ajax calls. every time the state will change, your component will re-render

Output object name other than React with jsx syntax

with React v0.12 the #jsx pragma is gone which means it is no longer possible to output jsx with anything other than the React.METHODNAME syntax.
For my use case I am trying to wrap the React object in another object to provide some convenience methods thus, in my component files, I want to be able to write:
var myConvenienceObject = require('React-Wrapper');
var Component = myConvenienceObject.createSpecializedClass({
render: function () {
return <div />
}
})
However the jsx compiler automatially converts <div /> into React.createElement("div", null)
With older versions of React it was possible to handle this using the pragma at the top of the file. However, since that has been removed, I was wondering if there was any way currently to change the name of the object compiled by jsx so <div /> would be transformed into myConvenienceObject.createElement("div", null)
No, it's no longer possible to use a custom prefix for JSX. If you need to do this, you'll need to modify the JSX transform code, or create a fake React.
var React = require('react'), FakeReact = Object.assign({}, React, {
createElement: function(component, props, ...children){
// ...
// eventually call the real one
return React.createElement(component, props, ...children);
}
});
module.exports = FakeReact;
And then to use it you import the fake react and call it React.
var React = require('fake-react');
// ...
render: function(){ return <div />; }
If you would like to make some elements contains in your myConvenienceObject, you could consider the children props as shown in the doc. But this may need some changes in the myConvenienceObject too, to accept the children.
By the way, i'm not sure where is this createSpecializedClass functions comes from and what it does

Resources