React Hight Order Component - Can not use child components in enhanced component - javascript

I am trying to implement a Higher Order Component in my react app. I have a base form component with all general login, & then I made a ContactForm component which wraps this general component.
The issue is my page become unresponsive & give maximum stack exceeded error when I try to run it. After some research I found that the issue is calling some custom components in render method of general form component. But that is the same syntax I use everywhere in app.
Why react cause this issue & how to resolve it, Am I implementing the HOC logic in wrong way? I need to import those components in the Form since they handle some logic by themselves & help to separate concerns.
Below is code for both general & HOC component.
Contact Form Component
import React, { Component } from 'react'
import Form from './form'
const createForm = FormComponent =>
class extends Component {
render() {
return <FormComponent {...this.props} />
}
}
const ContactForm = createForm(Form)
export default ContactForm
Base Form Component
import React, { Component } from 'react'
import InputText from './input-text'
import SubmitButton from './submit'
class Form extends Component {
render() {
return (
<div className="page-form">
<div className="page-form-fields clearfix">
<InputText/>
</div>
<SubmitButton />
</div>
)
}
}
export default Form
Input Text
class InputText extends Component {
render() {
const { type, icon, label, name, placeholder, maxlength, value, disabled, error, errorText } = this.props
return (
<div className={`finput ${label && 'labeled'} ${error ? 'has-error' : ''}`}>
<input
type={type || 'text'}
name={name}
className={`textfield w-input ${error ? 'has-error' : ''}`}
maxLength={maxlength}
placeholder={placeholder}
value={value}
disabled={disabled}
onChange={e => this.props.onChange(e)}
onBlur={e => this.props.onBlur && this.props.onBlur(e)}
/>
<label className="fip-label">
{label}
</label>
{error &&
<span className={`fip-info ${error && 'error'}`}>
{errorText}
</span>}
{icon && <i className={`icon icon-${icon}`} />}
</div>
)
}
}
Submit Button
import React, { Component } from 'react'
class SubmitButton extends Component {
render() {
const { response, pending } = this.props
return (
<div className="page-form-submit tright half-top-margin">
{response &&
<h4>
{response}
</h4>}
<button type="button" className="btn" onClick={e => this.props.onSubmit()} disabled={pending}>
Submit
</button>
</div>
)
}
}
export default SubmitButton

It runs fine here,
const {Component} = React
class Form extends Component {
render() {
return (
<div className="page-form">
<div className="page-form-fields clearfix">
<input type="text" />
</div>
<button>Submit</button>
</div>
)
}
}
const createForm = FormComponent =>
class extends Component {
render() {
return <FormComponent {...this.props} />
}
}
const ContactForm = createForm(Form)
ReactDOM.render(<ContactForm />, 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>

Related

How to update react component state from one component to another, and call any functions from any component

I am very new to react, when I put everything in one place, it works fine. But when I split it into components, everything went wrong.
I have two files App.js and Activity1.js
Activity1.js contains an input with an event handler attached to it. This input is simply wrapped inside a div.
The input was initially in App.js but I extracted it to Activity.js.
The input has a sibling, a div where I echo whatever the user types in the input, by updating the props state. How can I update the state. Your time and interest is appreciated.
Here's my code:
App.js
import './App.css';
import React from 'react';
import Activity1 from './f/Activity1';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {value:15};
}
checkInput = e => {
this.setState({value: e.target.value});
}
render(){
return (
<div className="p-2">
<div>
<Activity1 />
</div>
</div>
)
}
}
export default App;
Here's Activity1.js
import React from "react";
class Activity1 extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<div>Enter Number</div>
<input className="form-control" onChange={this.checkInput} />
<div className="p-2 mt-3">{this.state.value}</div>
</div>
)
}
}
export default Activity1;
Hope this solves the problem.
app.js
...
<Activity1 checkInput = {this.checkInput} inputValue = {this.state.value}/>
...
Activity1.js
...
render() {
const {checkInput, inputValue} = this.props;
...
<input className = "form-control" onChange = {checkInput} />
<div className = "p-2 mt-3"> {inputValue} </div>
You can pass a function as a prop to the other component.
<div>
<Activity1 checkInput={this.checkInput} inputValue = {this.state.value}/>
</div>
In your Activity1 component,
const {checkInput, inputValue} = this.props;
onChangeEventHandler= () => {
checkInput();
}
and
<input className = "form-control" onChange = ={this.onChangeEventHandler} />
<div className = "p-2 mt-3"> {this.inputValue} </div>
https://dev.to/vadims4/passing-down-functions-in-react-4618
You can use a Callback function
<Activity checkInput = {this.checkInput} inputValue = {this.checkInput.bind(this)}/>

How to get label values dynamically and adding the numbers together from different input with reactjs

Created a Div and inside it I have label element and input element, I want to get different label values in each div. How to re-use my div component
instead of coding the same code again.
I have tried to search in Stackoverflow plus googles, Haven't received a better answer.
Here I have created div element with just label and input element and then I have rendured this component in App.js file:
How can I reuse the same code/component to create 2 more div and having different labels values in it? Ho can I add numbers together from different input ( which I am getting from different components input)
Appreciate all your help!
import React, { Component } from 'react';
import './calculator.css';
class Boxes extends Component {
state = {
inputOne: '',
inputtwo: '',
inputthree: ''
}
getInputValue = (e) => {
const value = e.target.value;
console.log('value: ', value);
this.setState({
inputOne: Number(e.target.value)
});
}
render() {
const { value } = this.props // destructuring
const {inputOne, inputtwo, inputthree } = this.state
return (
<div className="boxes">
<label className="boxeslevel" htmlFor="text">
{value}
</label>
<input
name="text"
type="text"
onChange={this.getInputValue}
/>
</div>
);
}
}
export default Boxes;
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="wrapper">
<Boxes value= {"Value 1:"} onChange={this.props.onChange}/>
<Boxes value= {"Value 2:"} onChange={this.props.onChange}/>
<Boxes value= {"Value 3:"} onChange={this.props.onChange}/>
<ShowResult />
</div>
);
}
}
export default App;
You should pass a prop to your componente to be reuse. As you notice you are using local component state in your component, like const {value} = this.state try the same approach but with props like const {value} = this.props and then passing that prop in the component usage like
<Boxes value={“label 1”}/>
<Boxes value={“label 2”}/>
That would work. Hope it help you
Remember you can use as many props you need and access them as the same way mention above
You can do something like this:
class Boxes extends Component {
render() {
const { value } = this.props // value coming from props
return (
<div className="wrapper">
<div className="firstBox">
<label htmlFor="text">
{value}
</label>
<input name="text" type="text" />
</div>
</div >
);
}
}
export default Boxes;
and in your app component something like this:
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="App">
<Boxes value={1}/>
<Boxes value={2}/>
<Boxes value={3}/>
</div>
);
}
}
export default App;
Here is live demo link
You have to use props instead of state in your Boxes component. Then you can pass the required props from the App component.
App.js
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="App">
<Boxes value={"Value 1"}/>
<Boxes value={"Value 2"}/>
<Boxes value={"Value 3"}/>
</div>
);
}
}
export default App;
Boxes.js
import React, { Component } from 'react';
import './calculator.css';
class Boxes extends Component {
render() {
const { value } = this.props // destructuring
return (
<div className="wrapper">
<div className="firstBox">
<label htmlFor="text">
{value}
</label>
<input name="text" type="text" />
</div>
</div >
);
}
}
export default Boxes;

How to pass a value between 2 components?

I have 2 separate components, Form component is the step 1 where you enter your name, then by clicking <Link /> you go to the next step which is Welcome component.
How can I pass the name value {this.state.value} from Form component to Welcome component so it can retrieve what was typed in the Form component.
Form component:
import React from 'react';
import Link from 'react-router';
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ''
};
}
render() {
return (
<div className='root'>
<p>Setup the engine analysation presentation to demo incubation functionality.</p>
<div className='fieldRow'>
Name
<input type="text" autoFocus value={this.state.value} placeholder='Enter Name...' />
</div>
<div className='btnWrapper'>
<Link to='/welcome' >Access Demo</Link>
</div>
</div>
);
}
}
export default Form
Welcome component:
import React from 'react';
class Welcome extends React.Component {
render() {
return (
<div className='root'>
Welcome <!-- Name Input from Form component -->
</div>
);
}
}
export default Welcome;
You can pass it as state like this
<Link to={{
pathname: '/welcome',
state: {
name: this.state.value
}
}}>Access Demo</Link>
Then get it on welcome page (component) using withRouter
const { location } = this.props;
const name = location && location.state && location.state.name;

How to make/access state using props in react?

I made an app with multiple components and want their state to be accessed using parent/main app, I'm not sure how to get it. what i'm trying to do is when i change state in main "App" the component state should change. One of the component is 'checkbox' and now i want to access its state using parent app, I made multiple attempts but not getting it done. my code goes like this..
This is Main 'App' code:
import React, { Component } from 'react';
import Checkbox from './checkbox';
import Radio from './Radio';
import ToggleSwitch from './ToggleSwitch';
import PrimaryButton from './PrimaryButton';
class App extends Component {
onClick(isClicked){
isChecked:true
};
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
/>
<RadioButton
onClick={this.onClick}
/>
</div>
);
}
}
export default App;
The component i want to access goes like this:
import React, { Component } from 'react';
class Checkbox extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
};
};
onCheck(){
this.setState({
isChecked: !this.state.isChecked
});
this.props.isClicked()
};
render() {
return (
<div>
<div
className={this.state.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
);
}
}
export default Checkbox;
You forgot to bind the onClick event in the app component, try this it will work :
class App extends Component {
onClick(isClicked){
console.log('isClicked', isClicked);
};
render() {
return (
<div id="form">
<Checkbox onClick={this.onClick.bind(this)}/>
</div>
);
}
}
If you already have onClick handler for the Checkbox I don't see why you couldn't just move the state up to the App component and just pass down a callback from there to the Checkbox that will update the parent state. That seems like a more React way to do it, to me.
class App extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
}
}
onClick = (isClicked) => {
this.setState({isChecked: !this.state.isChecked})
}
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
ischecked={this.state.isChecked}
/>
</div>
);
}
}
Component
class Checkbox extends Component {
onCheck(){
this.props.onClick()
}
render() {
return (
<div>
<div
className={this.props.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
)
}
}

How to render component again at the top level with the new props in React 0.14

In the new React.js 0.14 setProps method was deprecated form React.Component. According to documentation, now we should render component again with new props(using ReactDOM.render())
The question is how can I do this? Let's look at an example.
AddTaskForm.js
import React from 'react';
class AddTaskForm extends React.Component
{
onClick() {
this.setProps({
isVisible: false
});
}
render() {
return (
<form role="form">
<div className="row" className={ this.props.isVisible ? 'show' : 'hidden' }>
<input className="form-control" type="text" />
</div>
<button type="button" className="btn" onClick={this.onClick.bind(this)}>Add task</button>
</form>
);
}
}
export default AddTaskForm;
Todo.js
var React = require('react');
var ReactDOM = require('react-dom');
var AddTaskForm = require('./AddTaskForm');
class Todo extends React.Component
{
render() {
return (
<div>
<AddTaskForm isVisible="false"></AddTaskForm>
</div>
);
}
}
ReactDOM.render(<Todo />, document.getElementById('app'));
Btw. I am using ES6 stage 0, if you find yourself confused with syntax
Ok, I can't call setProps, i had to rerender AddTaskForm component in Todo.js. How can I do this in this case? I've read this article form react's blog but wrapper don't really help me.
You should not use setProps at all. Properties in React must be immutable data, so you can't change them. Looks like isVisible prop is really part of component state, because depends on it component decides to show or not to show itself. The best choice for such situations when after some change of data you need to update component is state. I would recommend to read this doc about state and what should and should not go to state
From your example:
<div>
<AddTaskForm isVisible="false"></AddTaskForm>
</div>
.. how do you know should AddTaskForm be visible? For now it's hardcoded. I suggest doing something like that:
render () {
let shouldFormBeVisible = ...// somehow get to know should it be visible or not
return (
<div>
shouldFormBeVisible ? <AddTaskForm /> : null
</div>
)
}
Here is a big advantage: you even don't need to render AddTaskForm and if isVisible is false then hide it. You don't render component if it isn't needed.
isVisible is a piece of mutable state, so it needs to be stored in state somewhere.
One way is to put it on the AddTaskForm:
import React from 'react';
class AddTaskForm extends React.Component
{
constructor(props, context) {
super(props, context);
this.state = { isVisible: true};
}
onClick() {
this.setState({
isVisible: false
});
}
render() {
return (
<form role="form">
<div className="row" className={ this.state.isVisible ? 'show' : 'hidden' }>
<input className="form-control" type="text" />
</div>
<button type="button" className="btn" onClick={this.onClick.bind(this)}>Add task</button>
</form>
);
}
}
export default AddTaskForm;
Todo.js
var React = require('react');
var ReactDOM = require('react-dom');
var AddTaskForm = require('./AddTaskForm');
class Todo extends React.Component
{
render() {
return (
<div>
<AddTaskForm />
</div>
);
}
}
ReactDOM.render(<Todo />, document.getElementById('app'));
Another way is to store it on the Todo component, but I think you have enough to get started.

Categories

Resources