Higher Order Component (self) wrapping in React - javascript

Good Evening !!
My question title might be off, but here is the problem i'm trying to address. I have a component (Content) which listens for DOM event and call Board (instance which facilitate communication between Containers and their consuming Applications).
import Board from '../Board';
class Content extends React.Component {
constructor(props){
super(props);
}
componentDidMount(){
window.addEventListener("message", this.handleCheck, false);
}
componentWillUnmount(){
window.removeEventListener("message", this.handleCheck, false);
}
handleCheck =(event) => {
const { board } = this.props;
board.call({
size: event.detail.size,
panel: event.detail.panel,
.....
})
}
render(){
return null
}
}
I can consume/call Content component as mentioned below,
import Manager from '../../Manager'
const Example = () => (
<div>
<Manager>
<Content pageType="A4" />
</Manager>
</div>
);
The Manager component utilizes the Board API to manage call requests, and maintains the state of it's children. The component provided as children to Manager should also support Board prop.
In Example component i would like to call <Content pageType="A4" /> instead of wrapping with <Manager> and somehow use the <Manager> within the Content component definition (inside the Content component to leverage Manager). i.e
const Example = () => (
<div>
<Content pageType="A4" />
</div>
);

Pretty sure you are just looking for the basic HOC implemenation...
function withManager(Component) {
class WithManager extends React.Component {
...withManagerStuff
render() {
return <Component/>
}
}
return WithManager;
}
and then where you want to use your components with the shared HOC (ContentWithManager) you can do something like - module.exports = withManager(Content)

This stuff gets complex quickly.
I may be off, as I am slightly confused with what you are trying to do. However, I think you need to pass the wrapped (child) component to the wrapping (parent) component.
Here are two HOC examples of how to do this:
Note: Examples use redux and react-router, but the same pattern should
work without redux or react-router.
Redirect HOC: redirect.hoc.js
Redirect HOC Example: trans.app.container.js
<!-- Redirect HOC Example Code -->
<Route component={RedirectHoc(MainContentContainer)} />
Authorization HOC: authorization.hoc.js
<!-- Authorization HOC Example Code -->
<Route exact path="/beer/add" component={AUTHORIZE_ADMIN(BeerAddComponent)}/>

Related

React: Inserting a child into an already-rendered parent

I'm new to React and having some difficulty trying to add a new child component to a component that has already been rendered.
I have an App component which initially contains a Main component (main menu).
I also have Popover components which I want to appear on top of Main when they are children of <App> (and hence siblings of <Main>).
These Popover components vary in number. Each <Popover> can contain buttons which launch another <Popover> over the top again. So the structure would be like
<App>
<Main></Main>
<Popover></Popover>
<Popover></Popover>
...
</App>
However, when the page first loads there are no Popover components open, and the<App> is rendered without any. Here is a stripped-down version of my code:
class App extends React.Component{
constructor(props){ super(props) }
render(){
return (
<div>{this.props.children}</div>
)
}
}
class Main extends React.Component{
constructor(props){ super(props) }
render(){
return (
//main menu stuff here
)
}
}
ReactDOM.render(<App><Main /></App>, root);
How can I add new <Popover>s to my <App> when the user clicks something? Before React I would simply do App.appendChild(Popover) kind of thing, but I'm quite lost here.
I should add that the elements the user will click to trigger an initial <Popover> are not contained within <Main>; they are outside of the <App>, as I am trying to slowly transition my existing page to using React. I think this could be part of my problem.
So basically in React, you have multiple ways of doing this, but to be more reliable you need to have data that represents the dynamic components you will render in your DOM. And to do this you need to create a state and a function that can add new information to your state. Then simply by sharing this function with your other components, you can trigger it from wherever you want, and this will update your state which will increase the amount of dynamic components you will render.
Take a look at this example
import { useState } from "react";
export default function App() {
const [popups, setPopups] = useState([]);
const addNewPopup = () => {
setPopups([...popups, { title: "I am a popup" }]);
};
return (
<div className="App">
<ChildComponent onClick={addNewPopup} />
{popups.map((p) => {
return <Popup title={p.title} />;
})}
</div>
);
}
function ChildComponent({ onClick }) {
return (
<div>
<p>I am a child component</p>
<button onClick={onClick}>Add new element</button>
</div>
);
}
function Popup({ title }) {
return <div>I am a popup with title = {title}</div>;
}

How can I pass a component as a prop into another component in React?

I am new to React and I have a Java background, so forgive if the wording of this question doesn't really make sense.
I would like to "pass" an instance of a component into another component (that uses the passed component in it's render() method)
How can I do this?
Sorry for the bad naming, but I hope you're able to see the different use cases from what I understand from your question:
// Component that receives another component being passed in its props
function Renderer1(props) {
return props.component
}
// Component that receives another component and creates an instance of it
// this way this component has more control of rendering the passed component
// and the props you want to pass to it
function Renderer2(props) {
return <props.component />
}
// Component being passed in props
function PropComponent(){
return <div>Hello world!</div>
}
// Rendered component, example 1
function Main1() {
return <Renderer1 component={() => <PropComponent />} />
}
// Rendered component, example 2, this one uses Renderer2 component
function Main2() {
return <Renderer2 component={PropComponent} />
}
I hope with these different examples you can get an idea of how to continue with what you're working on :)
The question is not very clear. But from what I understand, there can be multiple ways of doing this.
Component 1
class Component1 extends React.Component {
render() {
return <h1>Component 1</h1>;
}
}
Component 2
class Component2 extends React.Component {
render() {
return (
<React.Fragment>
<h1>Component 2</h1>
{children}
</React.Fragment>
}
}
MainComponent
class MainComponent extends React.Component {
render() {
return (
<Component2>
<Component1 />
</Component2>
}
}
Here, one 'instance' of Component1 is passed to Component2 which then renders the Component1 as one of its children.
Another way is to use Render Props. To understand Render Props in a better way, you can watch this Youtube tutorial.

How to pass an element between two components in reactJS

I recently have begun learning reactjs and I am having a hard time comprehending state and how it's used. I have built two stateless components (boxOne and boxTwo) and I have a property "Move Me" that I would like to pass between the two components on the click of a button (MoveButton). Below is the code to where I reached to before getting stuck
class MoveButton extends React.Component {
render() {
return (
<button className="thebutton">
Click To Move
</button>
);
}
}
class BoxOne extends React.Component {
render() {
return (
<div className="boxOne-container">
{this.props.name}
</div>
);
}
}
class BoxTwo extends React.Component {
render() {
return (
<div className="boxTwo-container">
</div>
);
}
}
function App() {
return (
<div>
<BoxOne name="Move Me" />
<BoxTwo />
<MoveButton />
</div>
);
}
ReactDOM.render(<App />,document.getElementById('container'));
Okay, so here is a codepen with everything working.
Here is the code for future generation in the event codepen dies before S-O (I think you can run it here as well??).
class Box extends React.Component {
render(){
return (
<div>
{this.props.name ? this.props.name : "nothing"}
</div>
);
}
}
class MoveButton extends React.Component {
render(){
return(
<button onClick={this.props.on_click_handler}>
Click Me
</button>
);
}
}
class App extends React.Component {
constructor(props){
super(props);
this.state = {
first_button: true
};
this.on_click_handler = this.on_click_handler.bind(this);
}
on_click_handler(){
this.setState({
first_button: !this.state["first_button"]
});
}
render() {
return (
<div>
<Box name={this.state["first_button"] ? "Move Me": null} />
<Box name={!this.state["first_button"] ? "Move Me": null} />
<MoveButton on_click_handler={this.on_click_handler} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
So, anyways... here's the explanation.
Basically what you want to do is have the higher level component deal with the state. In this case, we're talking about App. Eventually you'll start to learn where state should go, but generally you want it to be at the highest point that makes sense. Basically, in this case since the App component has the thing (the button) that is changing the state of the two Box we want the state there.
I make the actual function that deals with the click inside the App component, and pass it down to the sub component, MoveButton. I do this because the function is changing state in the App component, so it has to be there. I also had to bind the this in the constructor, which is this line: this.on_click_handler = this.on_click_handler.bind(this);. This just makes sure that this is always referencing the correct thing inside that function.
Then in that handler function I change the components state, which causes a re-render. I use the ternary operator to see which instance of Box I should be passing the "Move me" to. I also use the ternary operator in Box itself to either put the name, or "nothing" but you can change that whatever.
Hope that helps.
P.S: You don't need two different component classes for Box. They're the same thing, so just reuse the same component, but make two instances of it. Which is what I did here.
First off I'd strongly suggest to read the entire react documentation: https://facebook.github.io/react/docs/hello-world.html (or at the very least, to start off the whole quick start section, which covers all the basic you need). It covers pretty much all of react (React has quiet a small scope!).
You need to have some kind of state. Currently your class components (MoveButton, BoxOne and BoxTwo) have access to state but don't use it. Your App component defined as function does not have access to any kind of own state.
Your state needs to be in a common parent component, which you can then pass down to child components as props. The child components may be stateless. In your case that would be the App Component, which you could use a class for instead to make react state available, while the other three components you could rewrite to be stateless functions.
Now I don't understand what exactly you want to happen, I'll just assume you want to move the "Move me" text from one Box to the other on clicking the button. Therefore both boxes have the ability to display text, controlled by the parent. Both boxes could have a react prop called 'name', received by the parent (App). The button itself needs to emit an event (callback), defined in the parent and passed down to the button as prop. I'll call that prop 'handleEvent'.
The implementation could look like such:
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
function BoxOne(props) {
return (
<div>BoxOne: {props.name}</div>
);
}
function BoxTwo(props) {
return (
<div>BoxTwo: {props.name}</div>
);
}
function MoveButton(props) {
return (
<button onClick={props.handleEvent}>Click to Move</button>
);
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
boxOneName: 'Move me',
boxTwoName: ''
};
this.handleEvent = this.handleEvent.bind(this);
}
handleEvent() {
this.setState({
boxOneName: this.state.boxTwoName,
boxTwoName: this.state.boxOneName
});
}
render() {
return (
<div>
<BoxOne name={this.state.boxOneName}/>
<BoxTwo name={this.state.boxTwoName}/>
<MoveButton handleEvent={this.handleEvent}/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Everything used in the example is adressed within the react quick start guide.
Let me know if anything is still unclear :)!

Instance of reactJs component to render a component

Can I use an instance of a reactJS component to render a component.
Eg, Let's say my reactJS component is
class myComponent extends Component{
constructor(props){
super(props)
this.state = {
next:false
}
this.alertSomething = this.alertSomething.bind(this);
this.showNext = this.showNext.bind(this);
}
showNext(){
console.log('wow');
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
alertSomething(){
alert('Alert Something')
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
render(){
return(
<div className='column'>
</div>
)
}
}
export default myComponent
Now, inside my another component can I do;
let x = new displayContent.renderComponent();
render(
<x />
//or
<x.render />
)
// I tried both it didn't work, I thought there mush be some other way to achieve this, after all every component is just a javascript object.
Also at the same time, can I call function to make change in its state. Like.
x.someFunction();
where someFunctino is inside that react component, doing setState.
Is it possible? OR am I missing something?
Edit: I clearly understand that when you want to render a react component, you can always do, <component />.
This question is just out of curiosity, can this be done? if not, then why?, I mean how is that different from other javascript objects.
Well, you can use the React.createElement method to render a component:
React.createElement(Component, params)
but with JSX, this is the same:
<Component />
Refer to Multiple components in the React documentation.
This is not how you're supposed to use React. You don't have to handle object instantiations ; React do this for you. Use composition instead.
render() {
return (
<myComponent />
)
}
Also, if you want to set the state of a child component from a parent component, you should probably move the logic in the parent.
Probably you are looking for something like this.
import React, { Component } from "react";
import CamCapture from './CamCapture.js';
export default class ProctorVideoFeed extends Component{
constructor(props) {
super(props);
this.Camera = React.createElement(CamCapture);
}
//this.handleVideoClick = this.handleVideoClick.bind(this);
render(){
return(
<div>
<span>{this.Camera}</span>
<button onClick = {this.Camera.StopRecording}>Stop</button>
</div>
)
}
}
Here StopRecording is a function defined inside CamCapture class.

Is it a good idea to use connect() on many small reusable reactjs components in redux

Suppose I have a small reusable component called <LikePanel> which will be used across multiple pages in different types of parent components, like <BlogEntry> or <ItemEntry> or <ReplyEntry>.
import {connect} from 'react-redux'
import {likeAction} from './LikeAction'
class LikePanel extends React.Component{
render() {
return <ButtonGroup className={this.props.className}>
<Button onClick={()=>this.onClickLiking()}>
<Glyphicon glyph="thumbs-up"/>{this.props.like}</Button>
</ButtonGroup>
}
onClickLiking(type){
this.props.dispatch(likeAction());
}
}
const mapStateToProps = state => {
let obj = {};
obj[LIKE] = state[LIKE];
return obj;
}
export default connect(mapStateToProps)(LikePanel)
Example use cases of LikePanel:
class BlogEntry extends React.Component{
render(){
return this.props.data.entry.map((item)=>{
return <div>
{item.article}
<LikePanel like={item.like}/>
</div>
}
}
}
class ProductEntry extends React.Component{
render(){
return this.props.data.entry.map((item)=>{
return <div>
<ProductPanel data={item}/>
<LikePanel like={item.like}/>
</div>
}
}
}
So if a webpage has 20 blog entries there will be 20 connected <LikePanel> on the page, and there is a possibility in the future that extra components will be connected to redux. Is it a good practice to use connect() with such a small components like <LikePanel>?
It's absolutely fine. Use connect wherever it makes sense in your component hierarchy. One common pattern is to have a list component be connected and use mapState to retrieve the IDs of the data items in the list, render some <ListItem id={itemId} /> child component for each item, and have each child component also be connected and look up its own data by ID. Also see the Redux FAQ question at https://redux.js.org/faq/react-redux#should-i-only-connect-my-top-component-or-can-i-connect-multiple-components-in-my-tree .

Categories