React - How to create div and put into it a existing child - javascript

I would like to create div and put into it a existing child.
Let's say I am using some UI component which gives me some structure, it looks more or less like this. Now I would like to wrap part of this structure in my own div. In this case I want to wrap content into my own div.
<div class="heading"></div>
<div class="content"></div>
<div class="footer"></div>
So my Idea was:
useEffect(() => {
const wrapper = document.querySelector('.content');
wrapper && React.createElement('div', wrapper);
}, [dep])
But this does not create any div because I still see content without parent above

Just create a wrapper component and reuse it within your app.
export const Layout = ({ children, header, footer }) =>
<div className="layout">
<div className="header">{header}</div>
<div className="content">{children}</div>
<div className="footer">{footer}</div>
</div>
Layout.defaultProps = {
children: <></>,
header: <></>,
footer: <></>
}

enter image description here
<div>
<div className="heading">1</div>
<div className="content">2</div>
<div className="footer"> 3</div>
</div>
useEffect(() => {
const content = document.querySelector('.content');
const newContent = document.querySelector('.wrapper .content');
let chilItem = document.createElement('div');
let newItem = document.createElement('div');
newItem.className = 'wrapper';
chilItem.className = 'content';
newItem.appendChild(chilItem);
!newContent && content.parentNode.replaceChild(newItem, content);
}, []);

The approach in React is different.
You create a Layout component
Layout.jsx
export default function Layout(props) {
return <div>
<div class="heading">{props.heading}</div>
<div class="content">{props.children}</div>
<div class="footer">{props.heading}</div>
</div>
}
In your sub component
ComponentA.jsx
export default function ComponentA() {
return <Layout heading={<h1>Company Name</h1>} footer={<div>footer contents</div>}>
All you contents, this will be displayed in div
with class content. All contents here will be
available in props.childer of Layout component.
</Layout>
}
More details here - https://reactjs.org/docs/composition-vs-inheritance.html

Related

How to add className to component in react?

I have a navbar component that I created for react.
When I call this component on different pages, I need to change the classNames.
For example : I want my "" component to have a different class on one page and a different class on another page.
const ServicesCiso = () => {
return (
<div className="hero">
<NavBar/>
<div className...
How can i add className in this code ?
You can pass the className as props to this component and pass the preferred className on the page you are rendering it
const ServicesCiso = ({ className }) => {
return (
<div className={className}>
<NavBar/>
<div className...
<ServicesCiso className="my-class-name" />
You should pass the className from out side to your component via props however you also need a default class in init case
I have suggestion this library
https://www.npmjs.com/package/classnames ( combine classes )
example
View
- ServicesCiso.js
- ServicesCiso.css
import ./ServicesCiso.css;
import cn from('classnames');
const ServicesCiso = (props) => {
const {className} = props;
return (
<div className={cn('hello', className}}>
</div>
)
}

Reactjs make reusable custom modal

I am trying to make a modal reusable:
this is my component:
class OverleyModal extends Component {
constructor(props) {
super(props);
}
openModal = () => {
document.getElementById("myOverlay").style.display = "block";
}
closeModal = () => {
document.getElementById("myOverlay").style.display = "none";
}
render() {
return (
<React.Fragment>
<div id="myOverlay" className="overlay">
<div className="overlay-content">
<p>content goes there</p>
</div>
</div>
</React.Fragment>
)
}
}
export default OverleyModal;
The above component is working great for the purpose of modal, that is why i didn't include here CSS/style, the issue not about CSS.
I want, when i mount this component on any compoenet like thise below:
<overleyModal open={true} />
if open=true, the modal will be visiable
<overleyModal open={false} />
and if open={false}
the modal will disappear
You can see how i deal open and close modal in the coponent method openModal() and closeModal()
But i am going through the trouble to make it reliable, I just want to use open as props, nothing else. if open is true, it will appear and if false, it will disappear.
Can anyone please help me in this case?
You need to make use of props and control the opening and closing through it by conditionally rendering it. You can also make the content generic by passing it as props too
class OverlayModal extends Component {
render() {
const { open, content } = this.props
return open? <React.Fragment>
<div id="myOverlay" className="overlay">
<div className="overlay-content">
<p>{content}</p>
</div>
</div>
</React.Fragment>: null
}
}
export default OverlayModal;
and use it like
<OverlayModal open={true} content={content goes there'} />
or even better you can define the content as children to give you more styling options
class OverlayModal extends Component {
render() {
const { open, children} = this.props
return open? <React.Fragment>
<div id="myOverlay" className="overlay">
<div className="overlay-content">
{children}
</div>
</div>
</React.Fragment>: null
}
}
export default OverlayModal;
and using as
<OverlayModal open={true} ><p>content goes there</p></OverlayModal >
open can be a property value and modal can be rendered conditionally based on the prop value. There is no need to directly access dom element.
return props.open ? (
<div id="myOverlay" className="overlay">
<div className="overlay-content">
<p>content goes there</p>
</div>
</div>
) : null;

How to add same component inside components

I tried to do task below, but i am stuck, How can I structure my components in a way that, it will be possible for nesting same component inside component.
App.js file
render () {
return (
<main className="wrapper">
<div className="row">
<Container addBox = { this.addBox }
boxes = {this.state.containers}
changeColor={this.changeColor}
addContainer = {this.addContainer}
containers={this.state.containers}/>
</div>
</main>
);
}
Like you add Container in app.js, create Box component and add it to Container.js, set the props as you did in this one, something like this:
import Container from "./Container.js"
state={ data1 : "something" }
render () {
return (
<main className="wrapper">
<div className="row">
<Container addBox = { this.addBox }
propsAgain={this.state.data1}
changeColor={this.changeColor}
addContainer = {this.addContainer}
containers={this.state.containers}/>
</div>
</main>
);
Container.js:
import Box from "./Box.js"
render () {
const{propsAgain}=this.props // we pass it upper again
return (
<div className="row">
<Box props1 = {propsAgain}
</div>
);
Box.js:
render () {
const {props1, props2} = this.props // these are props to pass to parent component
return (
<div>{props1}</div>
);
If you want to pass the grandchildren components' data to the upper component, you can pass the props to one step up, define props again and pass it to one step up again

ReactJs - how to use multiple children in a component

I'm prefacing this with the fact I'm VERY new to ReactJs and probably trying to work out something quite basic.
I have this code with a custom piece of HTML:
Sample Component
const Sample = ({ title, children }) => {
return (
<div class="panel">
<div class="title">
{title}
</div>
<div class="body">
{children}
</div>
</div>
);
};
Side question - whats the correct name for the above? A fragment? It doesn't look to be a "component" but just learning the naming conventions for React too
Utilise Component
export default class ExampleComponent extends Component {
render() {
return <div class="page-body">
<div class="row">
<h1> Page 1 </h1>
<Sample title={<h1>Some title!</h1>}>
<p>This is my sample body!</p>
</Sample>
</div>
</div>
}
}
You can see that the content of the "Sample" element is taken automatically as children property but to set title I have to explicitly set "title" property. What I'd ideally like to do is something similar to the below:
Desired way to utilise Sample Component
export default class ExampleComponent extends Component {
render() {
return <div class="page-body">
<div class="row">
<h1> Page 1 </h1>
<Sample title="Some title!">
<Sample.Title>
<h1>This is my new way to do a title</h1>
</Sample.Title>
<Sample.Body>
<p>This is my sample body!</p>
</Sample.Body>
</Sample>
</div>
</div>
}
}
I've used this type of approach before with components others have created but want to do it myself now and finding it hard to get a simple example to do this.
Thanks in advance for any pointers!
I think what you want is called JSX Namespacing? Either way, you can instantiate Sample, and then add more components as properties of Sample (view it as an object):
import React from "react"
const Sample = ({ children }) => (
<div className="panel">
{children}
</div>
)
Sample.Title = (props) => <div className="title">{props.children}</div>
Sample.Body = (props) => <div className="body">{props.children}</div>
export default Sample
Note: React uses className rather than class since we are using JSX.
The Children utils suit can be helpful for your scenario.
import { Children } from 'react'
const Sample = ({ title, children }) => {
let _body, _title
Children.forEach(children, child => {
if (child.type === SampleTitle) {
return _title = child
}
if (child.type === SampleBody) {
return _body = child
}
})
if (!_title) _title = <div className='title'>{title}</div>
if (!_body) _body = <div className='title'>{children}</div>
return (
<div className='panel'>
{_title}
{_body}
</div>
)
}
const SampleTitle = ({ children }) => <div className='title'>{children}</div>
const SampleBody = ({ children }) => <div className='body'>{children}</div>
Sampe.Title = SampleTitle
Sample.Body = SampleBody
Now you can use Sample in multiple ways:
<Sample title="my title">
<div>my body</div>
</Sample>
<Sample title="my title">
<Sample.Body>my body</Sample.Body>
</Sample>
<Sample title="my fallback title">
<Sample.Title>my overriding title</Sample.Title>
<Sample.Body>my body</Sample.Body>
</Sample>
In that case you just have to extract the relevant containers into their own components:
const Sample = ({children }) => (
<div className="panel">{children}</div>
);
const Title = ({children}) => (
<div className="title">{children}</div>
);
const Body = ({children}) => (
<div className="body">{children}</div>
);
Sample.Title = Title;
Sample.Body = Body;
Also note that the correct prop for a css class is className.

React access parent's dom node from child component

I have a grid component as follow:
import React, { Component } from 'react';
import Action from './action.jsx';
class Grid extends Component {
constructor(props) {
super(props);
this.maxN = 110;
this.tempArray = [];
this.question;
}
getRandomN() {
var randomN = Math.floor((Math.random() * this.maxN) + 1);
if(this.tempArray.indexOf(randomN) === -1) {
this.tempArray.push(randomN);
}
else {
randomN = this.getRandomN();
}
return randomN;
}
getRandomQuestion() {
this.question = this.props.current.data.questions[this.getRandomN()];
return this.question;
}
render() {
this.getRandomQuestion();
return (
<section className="game">
<div className="grid">
<div className="row">
<div ref="n1"></div>
<div ref="n2"></div>
<div ref="n3"></div>
<div ref="n4"></div>
<div ref="n5"></div>
<div ref="n6"></div>
</div>
<div className="row">
<div ref="n7"></div>
<div ref="n8"></div>
<div ref="n9"></div>
<div ref="n10"></div>
<div ref="n11"></div>
<div ref="n12"></div>
</div>
<div className="row">
<div ref="n13"></div>
<div ref="n14"></div>
<div ref="n15"></div>
<div ref="n16"></div>
<div ref="n17"></div>
<div ref="n18"></div>
</div>
<div className="row">
<div ref="n19"></div>
<div ref="n20"></div>
<div ref="n21"></div>
<div ref="n22"></div>
<div ref="n23"></div>
<div ref="n24"></div>
</div>
</div>
<Action question={this.question} getRandomQuestion={this.getRandomQuestion.bind(this)}/>
</section>
);
}
}
export default Grid;
inside the "Action" component, based on the correct or wrong answer coming from "getNewQuestion" I need to access a random grid element from the grid component. (any random going from "n1" to "n24" as assigned to each ref attribute)
import React, { Component } from 'react';
class Action extends Component {
constructor(props) {
super(props);
this.state = {
question: props.question
}
}
getNewQuestion(e) {
console.log(this.state.question.correct_option);
let answerId = "option_" + this.state.question.correct_option;
if(e.target.getAttribute('data-question') == answerId) {
this.setState({
question: this.props.getRandomQuestion()
});
}
else {
console.log('wrong');
React.findDOMNode(this.refs.n1).classList.add('fdsdfsdfsdfsdfsfsdf');
}
}
render() {
let state = this.state;
return(
<div className="action">
<div className="action-question">
<h3>{state.question.question}</h3>
</div>
<div className="action-answers">
<p data-question="option_1" onClick={this.getNewQuestion.bind(this)}>{state.question.option_1}</p>
<p data-question="option_2" onClick={this.getNewQuestion.bind(this)}>{state.question.option_2}</p>
<p data-question="option_3" onClick={this.getNewQuestion.bind(this)}>{state.question.option_3}</p>
<p data-question="option_4" onClick={this.getNewQuestion.bind(this)}>{state.question.option_4}</p>
</div>
</div>
);
}
}
export default Action;
inside the "if" statment of the "getNewQuestion" I would like to do something like:
n2.classList.addClass('hidden');
I can't figure out how to access a parent's dom node from the "Action" component
Does the child really need to access the parent DOM directly? Shouldn't the parent Component know how to present itself? If so, then you can use callbacks that you pass down to the children, so that the children have the possibility to notify the parent when it should change.
const Child = ({modifyParent}) => (
<div onClick={ modifyParent } >Click me!</div>
);
const Parent = () => {
const modifyMyOwnStyle = event => {
// here you have easy access
// if you want to style the parent.
alert('Modifying style, based on child call');
}
return (
<Child modifyParent={ modifyMyOwnStyle }/>
);
};
ReactDOM.render(<Parent />, document.getElementById('root'));
Runnable JSFiddle demo here
You can get the ref of a component and pass this to its children like so:
render() {
return (
<div ref={node => this.node = node}>
<SomeChild parent={this.node} />
</div>
)
}
read more about it here: https://facebook.github.io/react/docs/refs-and-the-dom.html
However I have to say that doing this is usually a bad idea, and I would reconsider if you really need to pass the node, or if there is another way around the problem.
EDIT: As jonahe's comment shows you can usually get around the problem by passing a callback to the child component that you can fire when something needs to happen in the parent component
Better than accessing parent's DOM node directly, you can use a callback prop that does it for you.
Something like:
class Grid extends Component {
constructor(props) {
super(props)
this.accessRandomElement = this.accessRandomElement.bind(this)
}
accessRandomElement() {
// do you thing
}
render() {
this.getRandomQuestion()
return (
<section className="game">
...
<Action
question={this.question}
onAccessYourRandomElement={this.accessRandomElement}
///
/>
</section>
)
}
}
and then from inside Action you call this.props.onAccessYourRandomElement()

Categories