I'm creating my first React app, so apologies in advance. A newbie must learn as he goes.
But I'm a few hours into debugging, having gotten nowhere, and I'm hoping someone can clarify why this attempt to pass data into a React component, use prototype.map, and render a final component just isn't cutting it.
var imagedata = [{"id":"1"},{"id":"2"},{"id":"3"}];
var portraitPhoto = React.createClass({
render: function() {
return (
<div className="test">
<img src={"./build/assets/images/photos/square_raw/" + this.props.imagepath + ".jpg"}
className="full-width-portrait" />
</div>
);
}
});
var portrait = React.createClass({
getDefaultProps: function(){
return {
data: imagedata
}
},
render: function() {
var portraitEach = this.props.data.map(function (imaged,i) {
return (
<div className="portrait2">
<portraitPhoto imagepath={imaged.id}/>
</div>
);
});
return (
<div className="portrait-container">
{portraitEach}
</div>
);
}
});
React.render(
<portrait/>,
document.getElementById('portraits')
);
You need your React components to have uppercase names. React's help page says:
React's JSX uses the upper vs. lower case convention to distinguish
between local component classes and HTML tags
Simply having this should be enough:
var PortraitPhoto = React.createClass({
...
...
});
A demo on jsfiddle is here.
Related
I want to get the ref of the children's component.The nested relationship between the components is shown below:
<Demo1 /> ---> <Demo2 /> ---> <Demo3 />
how to get the ref of Demo3 in Demo1?
You can pass the ref inside of the props:
// -- sub-sub component
var SubSub = React.createClass({
render: function() {
return <div><sub ref={ this.props.subSubRef }>Sub-sub component</sub></div>;
}
});
// -- sub component
var Sub = React.createClass({
render: function() {
return <div><em>Sub component</em><SubSub subSubRef={ this.props.subRef } /></div>;
}
});
// -- root component
var Main = React.createClass({
render: function() {
// -- get the ref from the child
const refCallback = function( domRef ){
this._subSubDomRef = domRef;
}.bind( this );
// -- example: accessing the dom element in some way
const handleClick = function(){
if( this._subSubDomRef ){
this._subSubDomRef.innerHTML = this._subSubDomRef.innerHTML + '.';
}
}.bind( this );
// --
return <div>
<strong onClick={ handleClick }>Main component</strong>
<Sub subRef={ refCallback } />
</div>;
}
});
(Note that you might run into conflicts in the case that some library that you are using, uses the same prop name as you do. That's one reason why forwardRef is recommended)
Further information:
The official React documentation mentions forwarding refs prior to the availability of forwardRef
under exposing-dom-refs-to-parent-components,
and recommends the example in dom_ref_forwarding_alternatives_before_16.3.md.
Unfortunately this example uses createRef, which is also not available before v16.3.
You need to follow the comments there and adapt the example accordingly.
The React documentation for v0.14 can be found at web.archive.org.
forwardRef and createRef were introduced in version 16.3.0 (March 29, 2018):
2018-02-06 createRef (8dc8f88d5ae9fb96934ba43e3842b5dcf4074afd)
2018-03-14 forwardRef 16.3.0-alpha.2 (bc70441c8b3fa85338283af3eeb47b5d15e9dbfe)
I have a sub component that does not need to be loaded immediately that I want to split out. I am trying to conditionally load in a react component via require.ensure. I am not getting any console errors but I am also not seeing anything being loaded. Here is the code I am calling :
renderContentzones() {
if (this.props.display ) {
return require.ensure([], () => {
const Component = require('./content-zones/component.jsx').default;
return (
<Component
content={this.props.display}
/>
);
});
}
return null;
}
It is just rendering a blank screen currently (no errors). This previously worked when I used import 'displayComponent' from './content-zones/component.jsx' and just returned it like you normally would in react, instead of this require.ensure but. Not sure what I am doing wrong here, any idea how to make something like this work? Thanks!
This is one way to do it, using the state to show the dynamic loaded component:
constructor(){
this.state = {cmp:null};
}
addComponent() {
const ctx = this;
require.ensure(['../ZonesComponent'], function (require) {
const ZonesComponent = require('../ZonesComponent').default;
ctx.setState({cmp:<ZonesComponent />});
});
}
render(){
return (
<div>
<div>Some info</div>
<div><button onClick={this.addComponent.bind(this)}>Add</button></div>
<div>
{this.state.cmp}
</div>
</div>
);
}
When you press the button add the component will be shown.
Hope this help.
I'm really new to React, and I'm pulling my hair out trying to solve what seems to me to be a simple problem. Here's a picture of the component I've built.
Color Picking Component
What I'm trying to accomplish seems trivial, but literally every article I've read explaining what to do has told me something different, and not one of the solutions has worked. It breaks down to this: When a user clicks on a tag, it builds out a tray and loops through an array of colors to build color buttons. When a color button is clicked it needs to pass which color was clicked to its parent component and run a function to update its color. I've read about flux, event bubbling, binding "this" to a property, and none of those solutions has seemed to work. The React docs are basically useless for a newbie like myself. I want to avoid complicated event structures like flux at this point since I'm appending some simple components to an existing app that I didn't write in React originally.
Also, PS, This code is in JSX which makes much more sense to me than straight JS react. Thanks in advance for your help!
var colorsArray = ["#ED5851", "#9CCC64", "#337AEC", "#ff7a45", "#7E58C2", "#FFEB3B", "#78909C", "#FFFFFF", "#213a4b"];
var EditDrawer = React.createClass({
updateColor: function() {
console.log("New Color: " + i);
},
render: function(){
var passTarget = this;
return (
<div className="container-fluid animated fadeIn extra-fast-animation tag-edit-drawer">
<div className="row">
<div className="col-xs-12">
{colorsArray.map(function(object, i){
return <ColorButton buttonColor={object} key={i} />;
})}
</div>
</div>
</div>
);
}
})
var ColorButton = React.createClass({
render: function(){
var buttonStyle = {
backgroundColor: this.props.buttonColor,
};
return (
<div className="tag-edit-color-button" style={buttonStyle} >
</div>
)
}
})
The callback function should work. As you've mentioned in your previous comment you can use your captured this to access the updateColor function from the child:
var passTarget = this;
...
...
return <ColorButton
buttonColor={object}
key={i}
update={passTarget.updateColor} />
Or as Bogdan mentioned you can pass it through map after your callback function:
{colorsArray.map(function(object, i){
return <ColorButton
buttonColor={object}
key={i}
update={this.updateColor} />;
}, this)}
Your <ColorButton /> component should then be able to run a simple onClick function:
onClick={this.props.update}
And then you can simply make use of normal event targets in the parent component to capture the color of the button that was clicked:
updateColor: function(e) {
console.log(e.target.style.backgroundColor);
}
Here is a full DEMO to demonstrate.
You can just pass callback function into child from your parent component, as simple as this:
<ColorButton buttonColor={object} key={i} onColorSelect={this.updateColor}/>
(when using React.createClass all class methods are already bound to this, so you are not required to call .bind(this)).
Then from ColorButton component you can call this callback as this.props.onColorSelect(...).
JS Bin example: http://jsbin.com/fivesorume/edit?js,output
OK, this is pretty simple in React without using flux or redux, similar to passing down props from parent to child, here we can use callback function like this:
var colorsArray = ["#ED5851", "#9CCC64", "#337AEC", "#ff7a45", "#7E58C2", "#FFEB3B", "#78909C", "#FFFFFF", "#213a4b"];
var EditDrawer = React.createClass({
updateColor: function(i) {
alert("New Color: " + i);
},
render: function(){
return (
<div className="container-fluid animated fadeIn extra-fast-animation tag-edit-drawer">
<div className="row">
<div className="col-xs-12">
{colorsArray.map(function(object, i){
return <ColorButton buttonColor={object} key={i} updateColor={this.updateColor}/>;
}, this)}
</div>
</div>
</div>
);
}
});
var ColorButton = React.createClass({
updateColor: function() {
this.props.updateColor(this.props.buttonColor);
},
render: function(){
var buttonStyle = {
backgroundColor: this.props.buttonColor,
};
return (
<div className="tag-edit-color-button"
style={buttonStyle}
onClick={this.updateColor}>
this.props.buttonColor
</div>
)
}
});
I have a set of buttons created from an array, however I'm unsure how to set individual classNames for them. Is there an easy way to this?
var ButtonContainer = React.createClass({
render: function(){
var answerList = this.props.answerList.map(function(input, i){
return <SingleButton key={'button'+i} singleAnswer={input}/>
}.bind(this));
return <div> {answerList} </div>
}
})
var SingleButton = React.createClass({
render: function(){
return (
<div>
<button className='quiz-button'>{this.props.singleAnswer}</button>
</div>
)
}
});
I've tried className={this.props.key} but that doesn't seem to work. Thanks for any help!
Since React v0.12 key and ref are removed from props:
You can no longer access this.props.ref and this.props.key from inside
the Component instance itself. So you need to use a different name for
those props.
That is why setting className={this.props.key} wont work. But you can try this:
return <SingleButton key={'button'+i} className={'button'+i} singleAnswer={input}/>
and then
<button className={this.props.className}>{this.props.singleAnswer}</button>
Related question: This.key in React.js 0.12
This question already has answers here:
ReactJS convert HTML string to JSX
(12 answers)
Closed 2 years ago.
I am building something with React where I need to insert HTML with React Variables in JSX. Is there a way to have a variable like so:
var thisIsMyCopy = '<p>copy copy copy <strong>strong copy</strong></p>';
and to insert it into react like so, and have it work?
render: function() {
return (
<div className="content">{thisIsMyCopy}</div>
);
}
and have it insert the HTML as expected? I haven't seen or heard anything about a react function that could do this inline, or a method of parsing things that would allow this to work.
You can use dangerouslySetInnerHTML, e.g.
render: function() {
return (
<div className="content" dangerouslySetInnerHTML={{__html: thisIsMyCopy}}></div>
);
}
Note that dangerouslySetInnerHTML can be dangerous if you do not know what is in the HTML string you are injecting. This is because malicious client side code can be injected via script tags.
It is probably a good idea to sanitize the HTML string via a utility such as DOMPurify if you are not 100% sure the HTML you are rendering is XSS (cross-site scripting) safe.
Example:
import DOMPurify from 'dompurify'
const thisIsMyCopy = '<p>copy copy copy <strong>strong copy</strong></p>';
render: function() {
return (
<div className="content" dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(thisIsMyCopy)}}></div>
);
}
dangerouslySetInnerHTML has many disadvantage because it set inside the tag.
I suggest you to use some react wrapper like i found one here on npm for this purpose.
html-react-parser does the same job.
import Parser from 'html-react-parser';
var thisIsMyCopy = '<p>copy copy copy <strong>strong copy</strong></p>';
render: function() {
return (
<div className="content">{Parser(thisIsMyCopy)}</div>
);
}
Very Simple :)
UPDATE
in the latest version as usage explained:
// ES Modules
import parse from 'html-react-parser';
// CommonJS
const parse = require('html-react-parser');
....
//Parse single element
parse('<li>Item 1</li><li>Item 2</li>');
//Parse multiple elements
parse('<li>Item 1</li><li>Item 2</li>');
By using '' you are making it to a string. Use without inverted commas it will work fine.
const App = () => {
const span = <span> whatever your string </span>
const dynamicString = "Hehe";
const dynamicStringSpan = <span> {`${dynamicString}`} </span>
return (
<div>
{span}
{dynamicStringSpan}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
import { Fragment } from 'react' // react version > 16.0
var thisIsMyCopy = (
<Fragment>
<p>copy copy copy
<strong>strong copy</strong>
</p>
</Fragment>
)
By using '' the sets the value to a string and React has no way of knowing that it is a HTML element. You can do the following to let React know it is a HTML element -
Remove the '' and it would work
Use <Fragment> to return a HTML element.
To avoid linter errors, I use it like this:
render() {
const props = {
dangerouslySetInnerHTML: { __html: '<br/>' },
};
return (
<div {...props}></div>
);
}
You don't need any special library or "dangerous" attribute. You can just use React Refs to manipulate the DOM:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.divRef = React.createRef();
this.myHTML = "<p>Hello World!</p>"
}
componentDidMount() {
this.divRef.current.innerHTML = this.myHTML;
}
render() {
return (
<div ref={this.divRef}></div>
);
}
}
A working sample can be found here:
https://codepen.io/bemipefe/pen/mdEjaMK
Try Fragment, if you don't want any of above.
In your case, we can write
import React, {useState, Fragment} from 'react'
const thisIsMyCopy = Fragment('<p>copy copy copy <strong>strong copy</strong></p>')
render: function() {
return (
<div className="content">{thisIsMyCopy}</div>
);
}
If you using hook want to set it in a state somewhere with any condition
const [thisIsMyCopy, setThisIsMyCopy] = useState(<Fragment><p>copy copy copy <strong>strong copy</strong></p></Fragment>);
If anyone else still lands here. With ES6 you can create your html variable like so:
render(){
var thisIsMyCopy = (
<p>copy copy copy <strong>strong copy</strong></p>
);
return(
<div>
{thisIsMyCopy}
</div>
)
}
You can also include this HTML in ReactDOM like this:
var thisIsMyCopy = (<p>copy copy copy <strong>strong copy</strong></p>);
ReactDOM.render(<div className="content">{thisIsMyCopy}</div>, document.getElementById('app'));
Here are two links link and link2 from React documentation which could be helpful.