ReactJS: Create components, not using render for non-react libraries - reactjs

Can you, using React, create router Links (or other components) from data returned from ajax-calls? NOT using the render function.
Background: We have a large 3rd party non-react javascript library that dynamically renders HTML from an AJAX call. We control the input (i.e. the ajax-response), but not the output. I want to input links (a href) and get them rendered as React Router Links. To wrap the non-react component I have created a component which basically have two parts: componentDidMount where I initiate the components and render where I output a div (for the 3rd party javascript library). Ideally we would like to inject reactJS component directly from the ajax-response:
[{'textToRender': '<Link to="/home" title="home">home</Link>'}]
Unfortunately this would only render the text:
<Link to="/home" title="home">home</Link>
Any idea if this is possible?
UPDATE: The non-react component is somewhat complex but for the sake of this question let us say it takes one ajax-url parameter and renders output to that div. The nonreact component expects HTML input from the AJAX, but I have the ability to execute javascript before injecting the HTML into that component.
I.e. the non-react component fetches data from the AJAX call
and update its div.
So the init looks like this:
componentDidMount() {
$('#nonreact').NonReact({ 'ajax': 'http://someurl..', 'transform' : function(data) { //here I can run some JS-code prior to nonrect render; return data; } });
}
And my component render looks like this:
render() {
return (
<div id="nonreact"></div>
)
}

You could do something like this:
componentDidMount() {
$('#nonreact').NonReact({
ajax: 'http://someurl..',
transform: (data) => {
// 1. transform data to some intermediate format
// {to: '/home', title: 'home', text: 'home'}
const {text, ...props} = transform(data);
// 2. create React element and set it to `link` state
this.setState({
link: React.createElement(Link, props, text);
});
}
});
}
render() {
// 3. Use {this.state.link} here
...
}

In React, <Link to="/home" title="home">home</Link> is just the sugar for
React.createElement(
Link,
{ to: "/home", title: "home" },
"home"
);
It does is transformed into that before your code is executed. Simply placing the text <Link to="/home" title="home">home</Link> won't do anything special.
You will probably make your life easier if the response is more like
[{'textToRender': {to: "/home" title: "home" text: "home }}]
Then, in a component that actually renders these you would iterate over these and create Links for that, in render
render: function() {
var linksResponse = ... // how ever you get them
var elements = linkResponses.map(function(entry) {
return Object.keys(entry).map(function(text) {
var linkData = entry[text];
// real action happens here
var link = <Link to={linkData.to} title={linkData.title}>{linkData.text}</Link>;
return link;
});
});
return elements;
}

It's absolutely possible. At my current project I fetch a large chunk of markup from an API. This is normal HTML with a few custom tags in it. These custom tags have corresponding React components in my app. What you want to to is make us of a library such as html-to-react (https://github.com/mikenikles/html-to-react). The way this works is that it parses the markup string and creates an object that represents the DOM for that markup. This object is in turn rendered to a React element. You can have custom tag handlers, telling html-to-react what to do when it finds a non-standard tag in the markup.
It works something like this:
let markupstring = '<div>lots of markup, 100kb</div>' // String
let parsedMarkup = htmlparser.parseWithInstructions(markupstring, function(){return true;}, processingInstructions);
How to configure prosessingInstructions is documented in html-to-react documentation. parsedMarkup is a valid React element.

Related

How to force React to accept server markup

On the first load I render my markup completely filled with data on the server.
This works well and the client sees it as a static html till the client-side React takes over. But this client-side code throws the markup away.
I stopped React from requesting the data per AJAX on the first load (because it's already there), only if I navigate client-side with a react-router <Link> to it.
But I can't force it to simply let the markup be, till the user interacts with it.
You can use dangerouslySetInnerHTML attribute. For example, create a new component wrapper like this and set html property:
export default React.createClass({
render: function() {
return <div dangerouslySetInnerHTML={ this.createMarkup() }>
</div>;
},
componentDidMount: function() {
// attach some events
},
componentWillUnmount: function() {
// detach some events
},
shouldComponentUpdate: function() {
return false;
},
createMarkup: function() {
return {
__html: this.props.html
};
}
});

How to render component from variable and save props and context?

I'm creating several React Components that behave in the same way except of rendering data. I put similar logic into mixin, including render function. The only thing I pass is the additional component that is responsible for presenting data in required way.
var A = React.createClass({
mixins: [MyMixin],
MyComponent: B,
});
var B = React.createClass({
get_value: function() {
// should return some value using top-level context
},
render: function() {
var x = this.get_value()
}
})
MyMixin = {
// some logic
render: function() {
<div>
// some common markup
<this.MyComponent
// some props
/>
</div>
}
}
The problem here is that component B (which is rendered through variable in mixin) doesn't have top-level context, from parents. At the same time components in the 'common markup' block does have it. How could I render components in the way above and save top-level context?
You can't access the top level context because B is not inheriting or sharing anything with A. Your mixin is just a simple extension of shared functionality and you just render component defined in component A. There is nothing that binds A and B.
What you could do is pass the needed stuff in the props of B.
<div>
// some common markup
<this.MyComponent
parentProps={this.props}
parentState={this.state}
/>
</div>
What you really should do is add all the common code in the mixin and use that mixin in both of your components. Since render is NOT common for your components you should define the render in each component or make an other mixin for that purpose.

Setting the initial state in React components for progressive enhancement & Flux architecture

I've read on http://scotch.io/tutorials/javascript/build-a-real-time-twitter-stream-with-node-and-react-js and it describes a technique of taking over server rendered React components seamlessly:
Server renders into {{{markup}}} in handlebars, and pass initial state.
<section id="react-app">{{{ markup }}}</div>
<script id="initial-state" type="application/json">{{{state}}}</script>
Then on the client side javascript
/** #jsx React.DOM */
var React = require('react');
var TweetsApp = require('./components/TweetsApp.react');
// Snag the initial state that was passed from the server side
var initialState = JSON.parse(document.getElementById('initial-state').innerHTML)
// Render the components, picking up where react left off on the server
React.renderComponent(
<TweetsApp tweets={initialState}/>,
document.getElementById('react-app')
);
But in a flux architecture, such as described in this article http://scotch.io/tutorials/javascript/creating-a-simple-shopping-cart-with-react-js-and-flux, state is initialized in the getInitialState lifecycle method:
// Method to retrieve state from Stores
function getCartState() {
return {
product: ProductStore.getProduct(),
selectedProduct: ProductStore.getSelected(),
cartItems: CartStore.getCartItems(),
cartCount: CartStore.getCartCount(),
cartTotal: CartStore.getCartTotal(),
cartVisible: CartStore.getCartVisible()
};
}
// Define main Controller View
var FluxCartApp = React.createClass({
// Get initial state from stores
getInitialState: function() {
return getCartState();
},
// Add change listeners to stores
componentDidMount: function() {
ProductStore.addChangeListener(this._onChange);
CartStore.addChangeListener(this._onChange);
},
// Remove change listers from stores
componentWillUnmount: function() {
ProductStore.removeChangeListener(this._onChange);
CartStore.removeChangeListener(this._onChange);
},
// Render our child components, passing state via props
render: function() {
return (
<div className="flux-cart-app">
<FluxCart products={this.state.cartItems} count={this.state.cartCount} total={this.state.cartTotal} visible={this.state.cartVisible} />
<FluxProduct product={this.state.product} cartitems={this.state.cartItems} selected={this.state.selectedProduct} />
</div>
);
},
// Method to setState based upon Store changes
_onChange: function() {
this.setState(getCartState());
}
});
module.exports = FluxCartApp;
Which one is the right approach to setting state from a progressive enhancement point of view?
Thinking about progressive enhancement I like how flux and react work together.
I am using ReactJS and Flux in my current project and everything is clean and easy. All you have to be aware of is showing some discipline of creating new stores when it really is needed. I dont really like the eventEmitter stuff though. I just trigger my own events which I define in a seperate eventConstants.js file this allows me to have several components listening for different changes on the same store.
This really scales well.
Answering your question:
It does depend about your usecase. Ignoring that rendering an initial page on the server is great for SEO it does only make sence to render on the server if users should all see pretty much the same content. I like to keep client stuff on the client.
I hope this helped you

Using x-editable with reactjs, how to call editable function on items?

I am new to ReactJS, I am trying to create a Reactjs component that is a list of editable fields using x-editable.
According to x-editable documentation I need to call .editable() for each field, normally this is done accessing the element with jQuery.
How can I do it with React ? It has to be done when the component is mounted and I can't find a way to know when the component is rendered...
I would like to know the best way to achieve this ; I had a look at React refs but I am not sure it can help. So I ended up giving it a specific class, then using a selector
to call editable() on the fields, but it works only when the rendering has been done
and I don't find it very elegant.
JS(X) code:
var EditableField = React.createClass({
render: function() {
return <p>{this.props.name}: {this.props.value}</p>
}
});
in script code:
$(document).ready(function() {
$.fn.editable.defaults.mode = 'inline';
$(".editable_field").editable();
You should do it in the componentDidMount function. This function is called when the component is mounted and the DOM is ready. Read more about the lifecycle here: http://facebook.github.io/react/docs/component-specs.html
Example (using refs instead of class selector):
var EditableField = React.createClass({
componentDidMount: function() {
$(this.refs.editable.getDOMNode()).editable()
},
render: function() {
return <p>{this.props.name}: {this.props.value}</p>
}
});
Note that many "jquery plugins" will do heavy DOM manipulations and that does not always play well with React.
You can use react-x-editable(react version of x-editable).Currently not all option supported.I will try to support most of options.

ReactJS state vs prop

This may be treading that line between answerable and opinionated, but I'm going back and forth as to how to structure a ReactJS component as complexity grows and could use some direction.
Coming from AngularJS, I want to pass my model into the component as a property and have the component modify the model directly. Or should I be splitting the model up into various state properties and compiling it back together when sending back upstream? What is the ReactJS way?
Take the example of a blog post editor. Trying to modify the model directly ends up looking like:
var PostEditor = React.createClass({
updateText: function(e) {
var text = e.target.value;
this.props.post.text = text;
this.forceUpdate();
},
render: function() {
return (
<input value={this.props.post.text} onChange={this.updateText}/>
<button onClick={this.props.post.save}/>Save</button>
);
}
});
Which seems wrong.
Is it more the React way to make our text model property state, and compile it back into the model before saving like:
var PostEditor = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: this.props.post.text
});
},
updateText: function(e) {
this.setState({
text: e.target.value
});
},
savePost: function() {
this.props.post.text = this.state.text;
this.props.post.save();
},
render: function() {
return (
<input value={this.state.text} onChange={this.updateText}/>
<button onClick={this.savePost}/>Save</button>
);
}
});
This doesn't require a call to this.forceUpdate(), but as the model grows, (a post may have an author, subject, tags, comments, ratings, etc...) the component starts getting really complicated.
Is the first method with ReactLink the way to go?
Updating 2016:
React is changed, and explanation "props vs state" became very simple. If a component needs to change data - put it in a state, otherwise in props. Because props are read-only now.
What's the exact difference between props and state?
You can find good explanation here (full version)
Your second approach is more like it. React doesn't care about models so much as it cares about values and how they flow through your app. Ideally, your post model would be stored in a single component at the root. You then create child components that each consume parts of the model.
You can pass callbacks down to the children that need to modify your data, and call them from the child component.
Modifying this.props or this.state directly is not a good idea, because React will not be able to pick up on the changes. That's because React does a shallow comparison of your post prop to determine if it has changed.
I made this jsfiddle to show how data could flow from an outer to an inner component.
The handleClick method shows 3 ways to (im)properly update state:
var Outer = React.createClass({
getInitialState: function() {
return {data: {value: 'at first, it works'}};
},
handleClick: function () {
// 1. This doesn't work, render is not triggered.
// Never set state directly because the updated values
// can still be read, which can lead to unexpected behavior.
this.state.data.value = 'but React will never know!';
// 2. This works, because we use setState
var newData = {value: 'it works 2'};
this.setState({data: newData});
// 3. Alternatively you can use React's immutability helpers
// to update more complex models.
// Read more: http://facebook.github.io/react/docs/update.html
var newState = React.addons.update(this.state, {
data: {value: {$set: 'it works'}}
});
this.setState(newState);
},
render: function() {
return <Inner data={this.state.data} handleClick={this.handleClick} />;
}
});
From React doc
props are immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable state to the component. this.state is private to the component and can be changed by calling this.setState(). When the state is updated, the component re-renders itself.
From TrySpace: when props (or state) are updated (via setProps/setState or parent) the component re-renders as well.
A reading from Thinking in React:
Let's go through each one and figure out which one is state. Simply
ask three questions about each piece of data:
Is it passed in from a parent via props? If so, it probably isn't
state.
Does it change over time? If not, it probably isn't state.
Can you compute it based on any other state or props in your
component? If so, it's not state.
I'm not sure if I'm answering your question, but I've found that, especially in a large/growing application, the Container/Component pattern works incredibly well.
Essentially you have two React components:
a "pure" display component, which deals with styling and DOM interaction;
a container component, which deals with accessing/saving external data, managing state, and rendering the display component.
Example
N.B. This example is a probably too simple to illustrate the benefits of this pattern, as it is quite verbose for such a straightforward case.
/**
* Container Component
*
* - Manages component state
* - Does plumbing of data fetching/saving
*/
var PostEditorContainer = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: getPostText()
});
},
updateText: function(text) {
this.setState({
text: text
});
},
savePost: function() {
savePostText(this.state.text);
},
render: function() {
return (
<PostEditor
text={this.state.text}
onChange={this.updateText.bind(this)}
onSave={this.savePost.bind(this)}
/>
);
}
});
/**
* Pure Display Component
*
* - Calculates styling based on passed properties
* - Often just a render method
* - Uses methods passed in from container to announce changes
*/
var PostEditor = React.createClass({
render: function() {
return (
<div>
<input type="text" value={this.props.text} onChange={this.props.onChange} />
<button type="button" onClick={this.props.onSave} />
</div>
);
}
});
Benefits
By keeping display logic and data/state management separate, you have a re-usable display component which:
can easily be iterated with different sets of props using something like react-component-playground
can be wrapped with a different container for different behavior (or combine with other components to build larger parts of your application
You also have a container component which deals with all external communication. This should make it easier to be flexible about the way you access your data if you make any serious changes later on*.
This pattern also makes writing and implementing unit tests a lot more straightforward.
Having iterated a large React app a few times, I've found that this pattern keeps things relatively painless, especially when you have larger components with calculated styles or complicated DOM interactions.
*Read up on the flux pattern, and take a look at Marty.js, which largely inspired this answer (and I have been using a lot lately) Redux (and react-redux), which implement this pattern extremely well.
Note for those reading this in 2018 or later:
React has evolved quite a bit since this answer was written, especially with the introduction of Hooks. However, the underlying state management logic from this example remains the same, and more importantly, the benefits that you get from keeping your state and presentation logic separate still apply in the same ways.
I think you're using an anti-pattern which Facebook has already explained at this link
Here's thing you're finding:
React.createClass({
getInitialState: function() {
return { value: { foo: 'bar' } };
},
onClick: function() {
var value = this.state.value;
value.foo += 'bar'; // ANTI-PATTERN!
this.setState({ value: value });
},
render: function() {
return (
<div>
<InnerComponent value={this.state.value} />
<a onClick={this.onClick}>Click me</a>
</div>
);
}
});
The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.
The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.
Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'

Resources