In my below code I want to render duplicate elements by using React.createRef(). because in the long run, I have to render the same element in the dialog for the help screen.
So how can I render it in DOM?
By the below code, I can get ref of the div element but cant renders it in Dom.
export default class TestComponent extends React.Component {
state = {};
myRef;
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (
<React.Fragment>
<div ref={this.myRef}>
<h2>Hello World!!!</h2>
</div>
{this.myRef && <>{this.myRef.current}</>}
</React.Fragment>
);
}
}
Edit:
I have to pass this reference to a new component(HelpScreenComponent), which will render same element along with some extra UI as a Dialog.
My problem was to render duplicate components on overlay for first-time users to display them a help screen.
I got not the exact answer but solution to my problem by rending only inner Html.
In the above code by replacing line
{this.myRef && <>{this.myRef.current}</>}
with this
{this.myRef.current && <div dangerouslySetInnerHTML={{__html: this.myRef.current.innerHTML}}/>}
Related
I'm in a learning phase of react and I've been trying to nest style of parent in component in child component via class in react.js. How to do it?
What I've tried until now:
function Card(props) {
const classes = 'card' + props.className;
return (
<div className={classes}>
{props.children}
</div>
)
}
export default Card
I applied style on class 'card' in a CSS file.
Parent component JS code:
import Card from './UI/Card';
function ExpenseItem(props){
return (
<Card className="expense-item">
<ExpenseDate date={props.date} />
<div className="expense-item__description">
<h2>{props.title}</h2>
<div className="expense-item__price">{`₹ ${props.amount}`}</div>
</div>
</Card>
)
}
Now, there are various classes in parent component that are styled accordingly. And I'd like to nest those classes in child component for those style to work.
You can see in the code the way I tried to nest the classes, but it isn't working.
const classes = 'card' + props.className;
What am I doing wrong? And how should I correct it?
You missed a space after the card class name, otherwise i don't see any other issues in your code. Try below, hope it works
const classes = 'card ' + props.className;
Just one note, this will make your components dependent on each other. One of best things about React is that it allows you to have separation of concerns. So Card component is doing Card component staff, displaying some information and needs not be dependent on a parent in this case ExpenseItem.
One way to do it is to use styled-components.
I have this component imported that returns a bunch of cards but I want to style this in a row instead of a column and it seems the way to do that is to loop the component as a <li> and then adding css but I cannot seem to make the component loop correctly.
the component looks like this inside of the parent element:
<div id="newsFeed" className='feed'>
<Feed theme={this.state.theme} articles = {this.state.articles} />
</div>
I have tried solutions such as:
var feedContent = <Feed theme={this.state.theme} articles = {this.state.articles} />
///////////////////////
{feedContent.map(item => <Feed key={item} value={item} />)}
</div>
but cannot seem to find any luck.
Any help would be greatly appreciated
map is a built in array method that is used a bunch in React. You need to use it on an array or else you will throw an error. I am assuming the value for articles is an array here:
//Feed component
class Feed extends React.Component {
constructor(props) {
super(props);
this.state = {
articles = []
};
}
componentDidMount = () => { // maybe call an API to populate the articles array }
render = () => {
return (
<ul className="someClass" >
{this.state.articles.map((item, index) => <li key={index} className="someOtherClass">{item}</li>)}
</ul>
);
}
}
alternatively you could create a li component, perhaps called FeedItem, import it and map it with the value prop from each item in the articles array.
// render method for Feed Component
render = () => {
return(
<ul className="someClass">
{this.state.articles.map((item, index) => <FeedItem key={index} value={item} />)}
</ul>
);
}
// FeedItem component
const FeedItem = ({value}) => {
return(
<li className="someOtherClass">{value}</li>
);
}
so, you are using map to create a list with the items in your articles array, and the map function loops through each article and returns a list component. Hopefully this helps! here's the React docs for reference: https://reactjs.org/docs/lists-and-keys.html
note: React docs advise against using an index as a key, but I don't know if your article array elements contain something unique. If they do (like an id of some kind), use that instead of index.
I think you need to change the approach.
I'd recommend you create an Article component, example:
function Article({ title }) {
<div>
{title}
<div>
}
After that, you might use the articles array to show each one:
//Feed component
this.state.articles.map((article, i) => <Article title={article.title}>)
In that way you can stylize the articles component as you want.
I was able to figure it out with simple CSS believe it or not. Basically <Feed /> was wrapped in a div in the parent component and was not responding to Flexbox CSS code, however, After I used changed the className of the div that was wrapping the component inside of its <div> within its own file the div responded to CSS! Thank you so much for your help everyone, I appreciate it!
Have you tried adding a className to the div that is the parent of the cards? Use that class to apply a flex display for example, and see what that gives you. If Newscard has a fixed width of 100% by chance, of course you'll need to adjust that to a small percentage / width to suit your needs.
I'm using React Big calendar (https://github.com/intljusticemission/react-big-calendar) and I'm working on some responsive styling which involves detaching the overflow-x (horizontal scrollbar) of a div specifically .rbc-agenda-view and attaching it to the browser window. For reference .rbc-agenda-view renders within the .rbc-calendar div i.e. the BigCalendar component.
My question is: How can I use useRef() on the .rbc-agenda-view if I don't have access to it's component. The BigCalendars component structure does not allow you to drill down to the inner components.
Any help with this would be appreciated.
Thanks in advance.
I think you need to create the ref in a parent component (useRef or React.createRef) and pass it along to the component you are interested in.
Something like:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <MyBigCalendarWrapper ref={this.myRef} />;
}
}
I wrote a react component in render props way,it will call children function with 3 react component object ( not sure the name exactly, the variable generated by executing jsx (<div>...</div>) );
<PaginatedTable> Usage example:
<PaginationTable data={data} ...otherprops>
{({ SearchBar, Table, PaginationBar })=>
(<div>
{SearchBar}
{Table}
{PaginationBar}
</div>)
}
</PaginationTable>
with render props, I'm so glad that I can custom these 3 child component object very easily such as rearrange order or adding custom elements between these three.
{({ SearchBar, Table, PaginationBar })=>
(<div>
{PaginationBar}
<h1> my custom search bar text </h1>
{SearchBar}
{Table}
</div>)
}
But now I wish more than arrange order inside , I wish I can move {SearchBar} out of to the same layer of 's sibling 's children such as this picture.
working demo: https://codesandbox.io/s/23q6vlywy
I thought this may be anti-pattern to the unidirectional data flow of React.
Extract {SearchBar} to another independent component then use it as <SearchBar ... /> inside of <ToolBarArea /> is what I learnd from React Doc.
But in this way, I have to do "lifting state up" and write similar function and states already had in <PaginationTable /> like below **text** parts are functions and states already had in <PaginationTable />
class ToolBarArea extends Component{
render(){
return(
<div>
// text
<SearchBar onChange={**this.props.onSearchBarChange**} />
//.... other text or elements
</div>);
}
}
class ContainerArea extends Component {
state={
**searchBarText:'',**
tableData : [{...}, {...}]
}
**onSearchBarTextChange = (event)=>{
this.setState({ searchBarText: event.target.value });
}
filterdTableData = ()=> this.state.tableData.filter(d=>d.name.includes(this.state.searchBarText);
**
}
I really hope there is a way I can simply move the variable {SearchBar} in the render props function out to without knowing is in the parent or parent's sibling or anywhere in the DOM tree.
such as
<ToolBarArea>
{SearchBar} // SearchBar from <PaginationTable />
</ToolBarArea>
Is there a way to reuseonSearchBarTextChange and filtedTableData functions and these **text** codes I already wrote in <PaginationTable /> ?
I believe you hit the nail on the head when you referred to lifting state. If you already wrote a similar function then your best option may be to 'abstract' that function so that it applies to both use cases. You could use a simple flag to differentiate the unique execution each needs. Then finally pass the function down to both components.
If you're adamant about avoiding this approach you could technically get around it by using event listeners to handle data transfer or watch variables in the window but this is for sure an anti-pattern.
I have to render multiple DOM elements from my JS.
Say I have divs like
<div id="div1"><div>
//Some Html tags
<div id="div2"><div>
//Some Html tags
<div id="div3"><div>
//Some Html tags
I need to render these three divs .
Each div will contain set of radio buttons. On click of any radio button in any div , I will execute a validation rest call , and based on the result I have to display only the valid radio buttons (that means I have to update each divs state.).
I used , something like this :
var divs=[
{"name":"one","element":"div1"},
{"name":"two","element":"div2"},
{"name":"three","element":"div3"}
];
for(var elem in divs){
ReactDOM.render(
<ElementBox name = {divs[elem].name} / > ,
document.getElementById(divs[elem].element)
);
}
But event handling is hectic if I use this kind of approach . Means I couldn't find any way to update other divs state after validation.
Is there any other way to render multiple containers in a single element ?
Yes there is: typical react is to only have 1 ReactDOM.render() to start the react-engine. And do all additional rendering within react components.
Something like this:
class ElementsBox extends React.Component {
render() {
return <div id={this.props.element}>{this.props.name}</div>
}
}
class ElementsContainer extends React.Component {
render() {
return (
<div>
{this.props.elements.map(function(element) {
return <ElementBox element={element} key={element.element}/>
});}
</div>
);
}
}
ReactDOM.render(<ElementsContainer elements={divs}/>,
document.getElementById('myreactrootinHTML'));
PS: unavoidable consequence of using react is that you always get a container within container, like this:
<div id='myreactrootinDOM'> // needs to be here so react can launch somewhere
<div> // react root can always only render 1 DOM element
<div id='div1'></div> // lower levels can have more than 1 component
<div id='div2'></div>
<div id='div3'></div>
</div>
</div>