Given the very simple page (having assumed React and react-router#4 have been imported):
// Current location: example.com/about
<Link to="/about/#the-team">See the team</Link>
// ... loads of content ... //
<a id="the-team"></a>
I would expect the above, upon clicking "See the team" would scroll down to the id'ed team anchor. The url correctly updates to: example.com/about#the-team, but it doesn't scroll down.
I have tried alternatives such as <a name="the-team"></a> but I believe this is no longer spec (nor does it work).
There are plenty of work arounds on github for react-router#v2 but they rely on the update callback present on BrowserRouter that is no longer present in v4.
Given a <ScrollIntoView> component which takes the id of the element to scroll to:
class ScrollIntoView extends React.Component {
componentDidMount() {
this.scroll()
}
componentDidUpdate() {
this.scroll()
}
scroll() {
const { id } = this.props
if (!id) {
return
}
const element = document.querySelector(id)
if (element) {
element.scrollIntoView()
}
}
render() {
return this.props.children
}
}
You could either wrap the contents of your view component in it:
const About = (props) => (
<ScrollIntoView id={props.location.hash}>
// ...
</ScrollIntoView>
)
Or you could create a match wrapper:
const MatchWithHash = ({ component:Component, ...props }) => (
<Match {...props} render={(props) => (
<ScrollIntoView id={props.location.hash}>
<Component {...props} />
</ScrollIntoView>
)} />
)
The usage would be:
<MatchWithHash pattern='/about' component={About} />
A fully fleshed out solution might need to consider edge cases, but I did a quick test with the above and it seemed to work.
Edit:
This component is now available through npm. GitHub: https://github.com/pshrmn/rrc
npm install --save rrc
import { ScrollIntoView } from 'rrc'
The react-router team seem to be actively tracking this issue (at the time of writing v4 isn't even fully released).
As a temporary solution, the following works fine.
EDIT 3 This answer can now be safely ignored with the accepted answer in place. Left as it tackles the question slightly differently.
EDIT2 The following method causes other issues, including but not limited to, clicking Section A, then clicking Section A again doesn't work. Also doesn't appear to work with any kind of animation (have a feeling with animation starts, but is overwritten by a later state change)
EDIT Note the following does screw up the Miss component. Still looking for a more robust solution
// App
<Router>
<div>
<Match pattern="*" component={HashWatcher} />
<ul>
<li><Link to="/#section-a">Section A</Link></li>
<li><Link to="/#section-b">Section B</Link></li>
</ul>
<Match pattern="/" component={Home} />
</div>
</Router>
// Home
// Stock standard mark up
<div id="section-a">
Section A content
</div>
<div id="section-b">
Section B content
</div>
Then, the HashWatcher component would look like the following. It is the temp component that "listens" for all route changes
import { Component } from 'react';
export default class HashWatcher extends Component {
componentDidMount() {
if(this.props.location.hash !== "") {
this.scrollToId(this.hashToId(this.props.location.hash));
}
}
componentDidUpdate(prevProps) {
// Reset the position to the top on each location change. This can be followed up by the
// following hash check.
// Note, react-router correctly sets the hash and path, even if using HashHistory
if(prevProps.location.pathname !== this.props.location.pathname) {
this.scrollToTop();
}
// Initially checked if hash changed, but wasn't enough, if the user clicked the same hash
// twice - for example, clicking contact us, scroll to top, then contact us again
if(this.props.location.hash !== "") {
this.scrollToId(this.hashToId(this.props.location.hash));
}
}
/**
* Remove the leading # on the hash value
* #param string hash
* #return string
*/
hashToId(hash) {
return hash.substring(1);
}
/**
* Scroll back to the top of the given window
* #return undefined
*/
scrollToTop() {
window.scrollTo(0, 0);
}
/**
* Scroll to a given id on the page
* #param string id The id to scroll to
* #return undefined
*/
scrollToId(id) {
document.getElementById(id).scrollIntoView();
}
/**
* Intentionally return null, as we never want this component actually visible.
* #return {[type]} [description]
*/
render() {
return null;
}
}
I've created a library called react-scroll-manager that addresses this issue and the other issues around scroll position with React Router. It uses this technique to navigate to hash links anywhere in the document without the need to wrap them individually. Simply wrap your Router component in a ScrollManager component:
class App extends React.Component {
constructor() {
super();
this.history = createHistory();
}
render() {
return (
<ScrollManager history={this.history}>
<Router history={this.history}>
...
</Router>
</ScrollManager>
);
}
}
You can link to any component with an id property:
<MyComponent id="mycomp">...</MyComponent>
Just include the id as a fragment in your Link target:
<Link to="#mycomp">...</Link>
The library is based on HTML5 and React 16, and it supports React Router 4 (and possibly earlier versions).
Related
I'm using the Segmented component by Ant Design. My application has some component like this:
...
import EmployeeCard from './EmployeeCard';
import ContractorCard from './ContractorCard';
function MyComponent() {
const [cardType, setCardType] = useState('Employee');
...
function changeCard(value) {
setCardType(value);
}
return (
...
<Segmented
options={['Employee', 'Contractor']}
onChange={changeCard)
value={cardType}
tabIndex={-1}
/>
{cardType === 'Employee'
? <EmployeeCard />
: <ContractorCard />
}
...
);
}
The EmployeeCard and ContractorCard have some input components in them that I want to be part of the overall tab flow on the page. However, I don't want the Segmented buttons themselves to be part of it. I set tabIndex={-1} on the Segmented component in order to take it out of the tab-flow, but apparently, internally, that component includes an Input component, which still has the default tabIndex={0}. I cannot figure out how to reach that component in order to set its tab index to -1.
class Headers extends React.Component {
render() {
const selected = this.props.selectedPane;
const headers = this.props.panes.map((pane, index) => {
const title = pane.title;
const klass = index === selected ? 'active' : '';
return (
<li
key={index}
className={klass}
onClick={() => this.props.onTabChosen(index)}>
{title}{' '}
</li>
);
});
return (
<ul className='tab-header'>
{headers}
</ul>
);
}
}
export default class Tabs extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedPane: 0
};
this.selectTab = this.selectTab.bind(this);
}
selectTab(num) {
this.setState({selectedPane: num});
}
render() {
const pane = this.props.panes[this.state.selectedPane];
return (
<div>
<h1>Tabs</h1>
<div className='tabs'>
<Headers
selectedPane={this.state.selectedPane}
//onTabChosen={this.selectTab}
panes={this.props.panes}>
</Headers>
<div className='tab-content'>
<article>
hellooooo
{pane.content}
</article>
</div>
</div>
</div>
);
}
}
I'm currently creating a 3 tab section where if you click on a tab, it gives you a new pane.
When looking at the render function I see a custom tag called Headers.
I know it coming from the Headers class at the beginning, but how does that format work? Is that a custom tag we building?
Also when looking at its properties such as onTabChosen, when it is deleted in the render method (for learning purposes) and I click on a selected tab, an error comes up saying
"_this.props.onTabChosen is not a function".
this.props.onTabChosen(index).. was written in the Headers class but not as a function correct?
I guess because I am also confused on how this.props.onTabChosen(index) works since onTabChosen was never declared anywhere, just input after props.
When looking at the render function I see a custom tag called "Headers".
That is not a custom tag. That is a React Component.
I know it coming from the Headers class at the beginning, but how does that format work?
Headers is either a function or a class (i.e. a constructor function).
The function will be called and the first argument passed to it will be an object with properties and values that match the props on the JSX element.
If you're going to use React then read a tutorial, this is very introductory level stuff for the framework.
It is covered very early on in both the MDN tutorial and the official React tutorial.
I guess because I am also confused on how this.props.onTabChosen(index) works since onTabChosen was never declared anywhere, just input after props.
It was declared, just not in the piece of code you shared.
I'm attempting to do an animation with React and CSS classes. I have created a live demo, if you visit it and click the Start button you will see the text fade in and up one by one. This is the desired animation that I am after.
However, there seems to be issues of consistency when you hit Start multiple times and I cannot pinpoint why.
The Issue: Below is a recording of the issue, you can see the number 1 is not behaving as expected.
live demo
The process: Clicking Start will cancel any previous requestAnimationFrame' and will reset the state to it's initial form. It then calls the showSegments() function with a clean state that has no classNames attached to it.
This function then maps through the state adding a isActive to each segment in the state. We then render out the dom with a map and apply the new state.
This should create a smooth segmented animation as each class gets dropped one by one. However when i test this in Chrome (Version 56.0.2924.87 (64-bit)) and also on iOS, it is very inconsistent, sometimes it works perfectly, other times the first DOM element won't animate, it will just stay in up and visible it's completed transitioned state with "isActive".
I tried to replicate this issue in safari but it worked perfectly fine, I'm quite new to react so i am not sure if this is the best way to go about things, hopefully someone can offer some insight as to why this is behaving quite erratic!
/* MotionText.js */
import React, { Component } from 'react';
import shortid from 'shortid';
class MotionText extends Component {
constructor(props) {
super(props);
this.showSegments = this.showSegments.bind(this);
this.handleClickStart = this.handleClickStart.bind(this);
this.handleClickStop = this.handleClickStop.bind(this);
this.initialState = () => { return {
curIndex: 0,
textSegments: [
...'123456789123456789123456789123456789'
].map(segment => ({
segment,
id: shortid.generate(),
className: null
}))
}};
this.state = this.initialState();
}
handleClickStop() {
cancelAnimationFrame(this.rafId);
}
handleClickStart(){
cancelAnimationFrame(this.rafId);
this.setState(this.initialState(), () => {
this.rafId = requestAnimationFrame(this.showSegments);
});
}
showSegments() {
this.rafId = requestAnimationFrame(this.showSegments);
const newState = Object.assign({}, this.state);
newState.textSegments[this.state.curIndex].className = 'isActive';
this.setState(
{
...newState,
curIndex: this.state.curIndex + 1
},
() => {
if (this.state.curIndex >= this.state.textSegments.length) {
cancelAnimationFrame(this.rafId);
}
}
);
}
render(){
const innerTree = this.state.textSegments.map((obj, key) => (
<span key={obj.id} className={obj.className}>{obj.segment}</span>
));
return (
<div>
<button onClick={this.handleClickStart}>Start</button>
<button onClick={this.handleClickStop}>Stop</button>
<hr />
<div className="MotionText">{innerTree}..</div>
</div>
)
}
}
export default MotionText;
Thank you for your time, If there any questions please ask
WebpackBin Demo
Changing the method to something like this works
render(){
let d = new Date();
const innerTree = this.state.textSegments.map((obj, key) => (
<span key={d.getMilliseconds() + obj.id} className={obj.className}>{obj.segment}</span>
));
return (
<div>
<button onClick={this.handleClickStart}>Start</button>
<button onClick={this.handleClickStop}>Stop</button>
<hr />
<div className="MotionText">{innerTree}..</div>
</div>
)
}
How this helps is that, the key becomes different than previously assigned key to first span being rendered. Any way by which you can make the key different than previous will help you have this animation. Otherwise React will not render it again and hence you will never see this in animation.
My React native application screen has View component with few text inputs. How can touch be detected on screen outside that View? Please help.
Thanks
As Andrew said: You can wrap your View with TouchableWithoutFeedback and adding a onPress you can detect when the view is tapped.
Another way to achieve that is having responses for touch events from the view.
/* Methods that handled the events */
handlePressIn(event) {
// Do stuff when the view is touched
}
handlePressOut(event) {
// Do stuff when the the touch event is finished
}
...
<View
onStartShouldSetResponder={(evt) => true}
onMoveShouldSetResponder={(evt) => true}
onResponderGrant={this.handlePressIn}
onResponderMove={this.handlePressIn}
onResponderRelease={this.handlePressOut}
>
...
</View>
The difference between Grant and move is that Grant is just when the user press, and Move is when the user is pressing and moving the position of the press
I don't take no for an answer, so I dug up a lot to find a solution matching my needs.
In my situation I have multiple components which need to collapse when I open another one.
This behavior has to be automatic, and easy to code-in by any contributor.
Passing parent refs to the children or calling a special global method are not acceptable solutions in my circumstances.
Using a transparent background to catch all clicks will not cut it.
This Question perfectly illustrates the need.
Demo
Here is the final result. Clicking anywhere except the component itself will collapse it.
WARNING
The solution includes usage of private React components properties. I know the inherent risks of using such an approach and I'm happy to use them as long as my app does what I expect and all other constraints are satisfied. Short disclaimer, probably a smarter, cleaner solution exists out there. This is the best I could do with my own limited knowledge of React.
First we need to capture all click in the UI, both for Web and Native. It seems that this is not easily done. Nested TouchableOpacityseem to allow only one responder at a time. So I had to improvise a bit here.
app.tsx (trimmed down to essentials)
import * as div from './app.style';
import { screenClicked, screenTouched } from './shared/services/self-close-signal.service';
// ... other imports
class App extends React.Component<Props, State> {
public render() {
return (
<div.AppSafeArea
onTouchStart={e => screenTouched(e)}
onClick={e => screenClicked(e)}>
{/* App Routes */}
<>{appRoutes(loginResponse)}</>
</div.AppSafeArea>
);
}
}
self-close-signal.service.ts
This service was built to detect all clicks on the app screen. I use reactive programming in the entire app so rxjs was employed here. Feel free to use simpler methods if you want. The critical part here is detecting if the clicked element is part of the hierarchy of an expanded component or not. When I write a mess like this I usually fully document why this was built this way in order to protect it from "eager" developers doing cleanups.
import { AncestorNodeTrace, DebugOwner, SelfCloseEvent } from '../interfaces/self-close';
import { GestureResponderEvent } from 'react-native';
import { Subject } from 'rxjs';
/**
* <!> Problem:
* Consider the following scenario:
* We have a dropdown opened and we want to open the second one. What should happen?
* The first dropdown should close when detecting click outside.
* Detecting clicks outside is not a trivial task in React Native.
* The react events system does not allow adding event listeners.
* Even worse adding event listener is not available in react native.
* Further more, TouchableOpacity swallows events.
* This means that a child TouchableOpacity inside a parent TouchableOpacity will consume the event.
* Event bubbling will be stopped at the responder.
* This means simply adding a backdrop as TouchableOpacity for the entire app won't work.
* Any other TouchableOpacity nested inside will swallow the event.
*
* <!> Further reading:
* https://levelup.gitconnected.com/how-exactly-does-react-handles-events-71e8b5e359f2
* https://stackoverflow.com/questions/40572499/touchableopacity-swallow-touch-event-and-never-pass
*
* <!> Solution:
* Touch events can be captured in the main view on mobile.
* Clicks can be captured in the main view on web.
* We combine these two data streams in one single pipeline.
* All self closeable components subscribe to this data stream.
* When a click is detected each component checks if it was triggered by it's own children.
* If not, it self closes.
*
* A simpler solution (with significant drawbacks) would be:
* https://www.jaygould.co.uk/2019-05-09-detecting-tap-outside-element-react-native/
*/
/** Combines both screen touches on mobile and clicks on web. */
export const selfCloseEvents$ = new Subject<SelfCloseEvent>();
export const screenTouched = (e: GestureResponderEvent) => {
selfCloseEvents$.next(e);
};
export const screenClicked = (e: React.MouseEvent) => {
selfCloseEvents$.next(e);
};
/**
* If the current host component ancestors set contains the clicked element,
* the click is inside of the currently verified component.
*/
export const detectClickIsOutside = (event: SelfCloseEvent, host: React.Component): boolean => {
let hostTrace = getNodeSummary((host as any)._reactInternalFiber);
let ancestorsTrace = traceNodeAncestors(event);
let ancestorsTraceIds = ancestorsTrace.map(trace => trace.id);
let clickIsOutside: boolean = !ancestorsTraceIds.includes(hostTrace.id);
return clickIsOutside;
};
// ====== PRIVATE ======
/**
* Tracing the ancestors of a component is VITAL to understand
* if the click originates from within the component.
*/
const traceNodeAncestors = (event: SelfCloseEvent): AncestorNodeTrace[] => {
let ancestorNodes: AncestorNodeTrace[] = [];
let targetNode: DebugOwner = (event as any)._targetInst; // <!WARNING> Private props
// Failsafe
if (!targetNode) { return; }
traceAncestor(targetNode);
function traceAncestor(node: DebugOwner) {
node && ancestorNodes.push(getNodeSummary(node));
let parent = node._debugOwner;
parent && traceAncestor(parent);
}
return ancestorNodes;
};
const getNodeSummary = (node: DebugOwner): AncestorNodeTrace => {
let trace: AncestorNodeTrace = {
id: node._debugID,
type: node.type && node.type.name,
file: node._debugSource && node._debugSource.fileName,
};
return trace;
};
interfaces/self-close.ts - Some boring typescript interfaces to help with project maintenance.
import { NativeSyntheticEvent } from 'react-native';
/** Self Close events are all the taps or clicks anywhere in the UI. */
export type SelfCloseEvent = React.SyntheticEvent | NativeSyntheticEvent<any>;
/**
* Interface representing some of the internal information used by React.
* All these fields are private, and they should never be touched or read.
* Unfortunately, there is no public way to trace parents of a component.
* Most developers will advise against this pattern and for good reason.
* Our current exception is an extremely rare exception.
*
* <!> WARNING
* This is internal information used by React.
* It might be possible that React changes implementation without warning.
*/
export interface DebugOwner {
/** Debug ids are used to uniquely identify React components in the components tree */
_debugID: number;
type: {
/** Component class name */
name: string;
};
_debugSource: {
/** Source code file from where the class originates */
fileName: string;
};
_debugOwner: DebugOwner;
}
/**
* Debug information used to trace the ancestors of a component.
* This information is VITAL to detect click outside of component.
* Without this script it would be impossible to self close menus.
* Alternative "clean" solutions require polluting ALL components with additional custom triggers.
* Luckily the same information is available in both React Web and React Native.
*/
export interface AncestorNodeTrace {
id: number;
type: string;
file: string;
}
And now the interesting part.
dots-menu.tsx - Trimmed down to the essentials for the example
import * as div from './dots-menu.style';
import { detectClickIsOutside, selfCloseEvents$ } from '../../services/self-close-signal.service';
import { Subject } from 'rxjs';
// ... other imports
export class DotsMenu extends React.Component<Props, State> {
private destroyed$ = new Subject<void>();
constructor(props: Props) {
// ...
}
public render() {
const { isExpanded } = this.state;
return (
<div.DotsMenu ...['more props here'] >
{/* Trigger */}
<DotsMenuItem expandMenu={() => this.toggleMenu()} ...['more props here'] />
{/* Items */}
{
isExpanded &&
// ... expanded option here
}
</div.DotsMenu>
);
}
public componentDidMount() {
this.subscribeToSelfClose();
}
public componentWillUnmount() {
this.destroyed$.next();
}
private subscribeToSelfClose() {
selfCloseEvents$.pipe(
takeUntil(this.destroyed$),
filter(() => this.state.isExpanded)
)
.subscribe(event => {
let clickOutside = detectClickIsOutside(event, this);
if (clickOutside) {
this.toggleMenu();
}
});
}
private toggleMenu() {
// Toggle visibility and animation logic goes here
}
}
Hope it works for you as well.
P.S. I'm the owner, feel free to use these code samples. Hope you will enjoy this answer and check Visual School for future React Native tutorials.
Put your View inside of TouchableWithoutFeedback, expand TouchableWithoutFeedback fullscreen and add onPress handler to it.
<TouchableWithoutFeedback
onPress={ /*handle tap outside of view*/ }
style={ /* fullscreen styles */}
>
<View>
...
</View
</TouchableWithoutFeedback>
You could try to use a Modal to create this behavior.
When you click the input field you show the Modal containing the multiple texts inputs. If you click outside the Modal it hides.
you can use
<View>
<TouchableWithoutFeedback
onPress={()=>{
//do something
}}
style={{position:'absolute',top:0 , right:0 , bottom:0 ,left:0}}/>
<YourComp></YourComp>
</View>
An easier solution, as stated here, is to detect the start of a touch action outside of the menu and close the menu in this case.
Keep in mind that for this to work, the first View that will catch the touch should take the full screen height, and that the app content as well as the menu should be inside. This allow the touch event to cascade correctly.
eg:
const [isOverflowMenuDisplayed, setOverflowMenuDisplayed] = useState(false)
const [childrenIds, setChildrenIds] = useState([])
const handleTouchShouldSetResponder = (event) => {
// To be able to close the overflow menu, the content of the screen need to be inside this top view, and detect if the pressed view if the menu item or the app content
if (childrenIds.length) {
if (childrenIds.includes(event.target)) {
return true
}
setOverflowMenuDisplayed(false)
return false
}
return false
}
return <View
onStartShouldSetResponder={handleTouchShouldSetResponder}
onMoveShouldSetResponder={handleTouchShouldSetResponder}>
<AppBar title={title} onLeftIconPress={onLeftIconPress} isCloseLeftIcon={isCloseLeftIcon}>
{actions}
{overflowAction && <AppBarActionOverflow onOpen={() => setOverflowMenuDisplayed(true)} />}
</AppBar>
<AppBarOverflowMenu
overflowAction={overflowAction}
isOpen={isOverflowMenuDisplayed}
childrenIds={childrenIds}
setChildrenIds={setChildrenIds}
onPress={() => setOverflowMenuDisplayed(false)}
/>
{children}
</View>
And the Overflow menu:
export const AppBarOverflowMenu = ({ isOpen, setChildrenIds, childrenIds, onPress, overflowAction }) => {
if (!isOpen) {
return null
}
return (
<View
style={thisStyles.menuContainer}
ref={(component) => {
if (component) {
const ids = component._children[0]._children.map((el) => el._nativeTag)
if (ids.length > 0 && (childrenIds.length !== ids.length || !childrenIds.includes(ids[0]))) {
setChildrenIds(ids)
}
}
}}>
<View style={thisStyles.menu}>
{React.cloneElement(overflowAction, {
onPress: () => {
onPress(false)
overflowAction.props.onPress()
},
})}
</View>
</View>
)
}
I'm displaying text that was stored in the database. The data is coming from firebase as a string (with newline breaks included). To make it display as HTML, I originally did the following:
<p className="term-definition"
dangerouslySetInnerHTML={{__html: (definition.definition) ? definition.definition.replace(/(?:\r\n|\r|\n)/g, '<br />') : ''}}></p>
This worked great. However there's one additional feature. Users can type [word] and that word will become linked. In order to accomplish this, I created the following function:
parseDefinitionText(text){
text = text.replace(/(?:\r\n|\r|\n)/g, '<br />');
text = text.replace(/\[([A-Za-z0-9'\-\s]+)\]/, function(match, word){
// Convert it to a permalink
return (<Link to={'/terms/' + this.permalink(word) + '/1'}>{word}</Link>);
}.bind(this));
return text;
},
I left out the this.permalink method as it's not relevant. As you can see, I'm attempting to return a <Link> component that was imported from react-router.However since it's raw HTML, dangerouslySetInnerHTML no longer works properly.
So I'm kind of stuck at this point. What can I do to both format the inner text and also create a link?
You could split the text into an array of Links + strings like so:
import {Link} from 'react-router';
const paragraphWithLinks = ({markdown}) => {
const linkRegex = /\[([\w\s-']+)\]/g;
const children = _.chain(
markdown.split(linkRegex) // get the text between links
).zip(
markdown.match(linkRegex).map( // get the links
word => <Link to={`/terms/${permalink(word)}/1`}>{word}</Link> // and convert them
)
).flatten().thru( // merge them
v => v.slice(0, -1) // remove the last element (undefined b/c arrays are different sizes)
).value();
return <p className='term-definition'>{children}</p>;
};
The best thing about this approach is removing the need to use dangerouslySetInnerHTML. Using it is generally an extremely bad idea as you're potentially creating an XSS vulnerability. That may enable hackers to, for example, steal login credentials from your users.
In most cases you do not need to use dangerouslySetHTML. The obvious exception is for integration w/ a 3rd party library, which should still be considered carefully.
I ran into a similar situation, however the accepted solution wasn't a viable option for me.
I got this working with react-dom in a fairly crude way. I set the component up to listen for click events and if the click had the class of react-router-link. When this happened, if the item has a data-url property set it uses browserHistory.push. I'm currently using an isomorphic app, and these click events don't make sense for the server generation, so I only set these events conditionally.
Here's the code I used:
import React from 'react';
import _ from 'lodash';
import { browserHistory } from 'react-router'
export default class PostBody extends React.Component {
componentDidMount() {
if(! global.__SERVER__) {
this.listener = this.handleClick.bind(this);
window.addEventListener('click', this.listener);
}
}
componentDidUnmount() {
if(! global.__SERVER__) {
window.removeEventListener("scroll", this.listener);
}
}
handleClick(e) {
if(_.includes(e.target.classList, "react-router-link")) {
window.removeEventListener("click", this.listener);
browserHistory.push(e.target.getAttribute("data-url"));
}
}
render() {
function createMarkup(html) { return {__html: html}; };
return (
<div className="col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-3 col-lg-8 col-lg-offset-2 post-body">
<div dangerouslySetInnerHTML={createMarkup(this.props.postBody)} />
</div>
);
}
}
Hope this helps out!