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 :)!
Related
I am dealing with two components and one store.Components are Child and Parent,Store is store. Parent when rendering, make the child component up and parent listens to store.Now I want to update the state of variable in Store, by exposing a method from Store. The parent pass this method as a call back to child. Child has a dialog box, and if user closes/dismiss that dialog box, the clearStoreInfo() should be called, which is passed by parent to child. But when i do so, I get error
React cannot update during an existing state transition (such as within render ) functional component
Store looks as :
class Stores {
........
........
........
#action.bound
clearStoreInfo = () => {
console.log(" clear info");
}
}
Parent Component:
import Store ........
class InfoContainer extends React.Component {
return (
<div id={"info"} className={"container"}>
<ButtonPanel store={Store} />
</div>
}
const ButtonPanel = (props) => {
return (
.....
.....
<div>
<ChildComponent clearStoreInfo={props.store.clearStoreInfo}/>
</div>
......
}
class ChildComponent extends React.Component {
render(){
const {clearStoreInfo} = this.props;
return (
////if -else ladder
clearStoreInfo(); // warning line.
<Dialog.......
onClose={clearStoreInfo}
/>
)
}
//Because of warning, the dialog box dont come. If i remove clearStoreInfo(), then dialog box works fine.
Is there any easy workaround given these components and store?
The wiring works fine, because I can see console log,based on if-else ladder, but its just the warning is messing things up internally.onClose is able to call the clearStoreInfo perfectally, but its when I manually call it, I am getting a warning.
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>;
}
I want to be able to abstract the way React component logic works separate the view logic from the handlers
class SuccessLabelWithIcon extends Label{
constructor(props){
super(props);
this.className = this.className + ' success-label';
}
render(){
return <div>
<div onClick={super.onClick}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work.
</div>
}
}
class Label extends React.Component{
constructor(props){
super(props);
this.className='plain-label';
}
clickHandler = () => {
console.log('Inherited');
}
onClick() {
console.log('Inherited');
}
render(){
return <span className={this.className}>
{this.props.children}
</span>
}
}
// Render it
ReactDOM.render(
<SuccessLabelWithIcon/>,
document.getElementById("react")
);
<div id="react"></div>
<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>
Working StackBlitzLink
Am I wrong with this approach? If No why is this not working for clickHandler, what I am looking at is extending component to have logic and the render functions as separate all the Button clicks and methods will be executed in the parent so that we can have separation of logic and then maybe share code across React and RN, but that is secondary?
My best bet is the clickHandler is attached to some prototypical property of the parent class as it a bound method and the click works as it a normal method not bound to the component but can we bypass this and can we mitigate this problem? And fire method only on click
Your approach is one which is not recommend and maybe even an anti-pattern to react's compositional model. Refer to Composition vs Inheritance section in the docs to see why composition is better over inheritance in react and how to handle some of the problem with composition where developers reach for inheritance. In your case, you should look at Specialization
You should almost always extend React components from React.Component.
class SuccessLabelWithIcon extends Label{
constructor(props){
super(props);
}
render() {
return (
// Specialization
<Label>Success</Label>
)
}
}
class Label extends React.Component{
constructor(props){
super(props);
}
clickHandler = () => {
console.log('Inherited');
}
onClick() {
console.log('Inherited');
}
render(){
return <span className="plain-label" onClick={this.onClick}>
{this.props.children}
</span>
}
}
<div id="react"></div>
<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>
Here is a forked working version of your stackblitz.
Working StackBlitzLink
Yes as u have stated your approach is not correct, in React you want to share code usage by components composition instead of inheritance.
I'm gonna use something similar to your example to help you understand the concept, lets say you want to create a base component called IconButton which will be a button with text alongside an icon, and you want to reuse that component to create two more components DangerIconButton (this is a button with an icon that is meant to represent a dangerous situation like a delete operation), and you want to create a SuccessfulIconButton (a button where you want to represent a desired action)
now based on our requirements we see that the functionality across all the three components is the same, basically a click handler but what is different is the visual representation (the icon and the styles applied to the button).
lets create our base component
class IconButton extends React.Component{
render(){
return <button onClick={props.onClick} style={props.style}>
<img src={props.icon} />
<span>button text</span>
</button>
}
}
now our two other components will be much simpler, and will use that base component
class SuccessfulIconButton extends React.Component{
render(){
// notice how i'm creating this component by composition of other components
// happyIcon and green are what makes this a successful butoon
return <IconButton onClick={props.onClick} style={{background: 'green'}} icon={happyIcon} />
}
}
class DangerIconButton extends React.Component{
render(){
// notice that i'm getting the onClick handler here through props, because u want the parent components of this component to have their specific handlers
return <IconButton onClick={props.onClick} style={{background: 'red'}} icon={dangerIcon} />
}
}
of course here u want better naming, and u still want to do some common styling for all your IconButtons like padding, and other stuff. but hopefully the concept came through
As mentioned by #hassaan-tauqir, its usually preferred to use composition rather than inheritance. But if you really want to do it, you can use the below code
class Label extends React.Component{
constructor(props){
super(props);
this.className='plain-label';
}
clickHandler = () => {
console.log('Inherited');
}
onClick() {
console.log('Inherited');
}
render(){
return <span className={this.className}>
{this.props.children}
</span>
}
}
class SuccessLabelWithIcon extends Label{
constructor(props){
super(props);
this.className = this.className + ' success-label';
}
render(){
return (<Label><div>
<div onClick={this.clickHandler}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work.
</div></Label>);
}
}
// Render it
ReactDOM.render(
<SuccessLabelWithIcon/>,
document.getElementById("react")
);
<div id="react"></div>
<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>
The reason clickHandler doesn't work is because you are using arrow functions to define it (basically it's doesn't have your SuccessLabelWithIcon context, and has instead the context of Label).
You can make it a simple method or you can simply use it with this instead of super (since you are extending the component).
class Label extends React.Component{
constructor(props){
super(props);
this.className='plain-label';
}
clickHandler = () =>{
console.log('Inherited');
}
onClick() {
console.log('Inherited');
}
render(){
return <span className={this.className}>
{this.props.children}
</span>
}
}
class SuccessLabelWithIcon extends Label{
constructor(props){
super(props);
this.className = this.className + ' success-label';
}
render(){
return (<Label><div>
<div onClick={this.clickHandler}>▲</div> // this works but fires initially too in StackBlitz but not in SO not sure why, but changing to clickHandler dosent work.
</div></Label>);
}
}
// Render it
ReactDOM.render(
<SuccessLabelWithIcon/>,
document.getElementById("react")
);
<div id="react"></div>
<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>
Hope this helps you
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.
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.