placing child component inside parent in reactjs - reactjs

I am trying to build a form with custom input fields. Problem is structure of form is not pre known. And i want it to abstract as many common functionalities as i can. So i created a form component which will actually take care of storing value of all input components and action on submit. Rest inside form how html should be that will be written by the user.
here is a snapshot:
a custom input field:
class InputField extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
id: this.props.id,
value: this.props.value || '',
valid: this.props.isValidationRequired || this.props.required ? true : false,
errorVisible: false,
errorMessage: ''
};
}
//different helper and conchange function
render() {
let props = this._getInputFieldProps();
return (<div className={this.props.fieldParentClass}>
<label for={this.props.id}>{this.props.name}</label>
<input {...props}/>
<span className={this.state.errorVisible ? 'show' : 'hide'}>{this.state.errorMessage}</span>
</div>)
}
}
export default InputField;
form:-
class FormComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
submitButton: {
buttonClasses: ['btn-default', 'vy-btn-secondary'],
buttonText: "SUBMIT",
}
};
}
//functions for storing values of children and submit
render() {
return <form role="form" class="vm-form">
<Button disabled={this.state.submitValid} onClick={this._onSubmit.bind(this)} button={this.state.submitButton}></Button>
</form>
}
}
export default FormComponent;
and caller class:-
class LeadDetails extends React.Component {
constructor(HttpService, $state, VymoDataService, props, context) {
super(props, context);
}
render() {
return (<FormComponent >
<InputField placeholder='hi' value="1"
type="text"
id="name"
maxlength="10"></InputField>
</FormComponent>)
}
}
so now i can wrap my input field component in some html wrapper and customise the look the way i want. But here only form is getting render not input field, neither its behaving as child.
Have I got it totally wrong in some way. What should have been my approach?

In your FormComponent render method, you need to render the "children", which will be located on this.props.children:
render() {
return <form role="form" class="vm-form">
{this.props.children}
<Button disabled={this.state.submitValid} onClick={this._onSubmit.bind(this)} button={this.state.submitButton}></Button>
</form>
}
The reason for this is when you go to actually create (instantiate) the form, you are doing the following:
<FormComponent >
<InputField placeholder='hi' value="1"
type="text"
id="name"
maxlength="10"></InputField>
</FormComponent>
The stuff in between the component tags are the "children". The children are passed to your component during instantiation (props.children), it's up to the component to render those children. The reason you are probably expecting the children to be rendered automatically is because React treats <ReactComponents> differently from <normal-dom-elements>.
Whenever react sees a <Tag> which begins with an upper case letter, it assumes that it's a react component and basically converts this:
<Tag foo="bar"><div>hello</div></Tag>
to something like this:
new Tag({
foo: "bar",
children: React.createElement('div', null, "hello")
})

Related

React.js Controlled Input in child component

I am trying to have a controlled input set up in a child component (the Search component). I wanted to keep the input state in the main App component so that I can access it in my apiCall method. I am getting the following error:
Warning: You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly.
However, I did add an onChange handler. I'm assuming the problem is that the onChange handler function is in the parent component and React doesn't like this. I did try moving the input to the main App component and worked fine (logged input to console).
Am I going about this wrong? And is there a way to set it up so that I can access the input from the Search component in the App component? I was hoping to keep most of my code/functions/state in the main App component.
Here is the App component
import React, { Component } from "react";
import './App.css';
import Header from './Components/Header'
import Search from './Components/Search'
import MainInfo from './Components/MainInfo'
import Details from './Components/Details'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
weather: null,
main: '',
wind: '',
loading: null,
cityInput: 'Houston',
city: 'City Name',
date: new Date()
};
this.apiCall = this.apiCall.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
cityInput: event.target.value
})
console.log(this.state.cityInput)
}
// Fetch data from OpenWeatherAPI
apiCall() {
this.setState({
loading: true
})
const currentWeather = fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${this.state.cityInput}&appid={apiKey}&units=imperial`
).then((res) => res.json());
const futureWeather = fetch(
`https://api.openweathermap.org/data/2.5/forecast?q=houston&appid={apiKey}&units=imperial`
).then((res) => res.json());
const allData = Promise.all([currentWeather, futureWeather]);
// attach then() handler to the allData Promise
allData.then((res) => {
this.setState({
weather: res[0].weather,
main: res[0].main,
wind: res[0].wind,
city: res[0].name
})
});
}
componentDidMount() {
this.apiCall();
}
render() {
return (
<div className="container-fluid bg-primary vh-100 vw-100 d-flex flex-column align-items-center justify-content-around p-3">
<Header />
<Search cityInput={this.state.cityInput} />
<MainInfo main={this.state.main} date={this.state.date} city={this.state.city} weather={this.state.weather} />
<Details main={this.state.main} wind={this.state.wind} />
</div>
);
}
}
export default App;
Here is Search component
import React, { Component } from "react";
class Search extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="row">
<div className="col-12">
<div className="d-flex">
<input className="form-control shadow-none mx-1" placeholder="Enter a city..." value={this.props.cityInput} onChange={this.handleChange}></input>
<button className="btn btn-light shadow-none mx-1" onClick={this.apiCall}>Test</button></div>
</div>
</div>
);
}
}
export default Search;
The Search component is indeed unaware of the implementation of the onChange function you have made in your App. If you really want to use a function from the parent (App) component in the child (Search), you'll need to add it as a property, as such:
<Search cityInput={this.state.cityInput} onChange={this.onChange} />
Then, you need to set it in the Child component's constructor:
constructor(props) {
super(props);
this.onChange = props.onChange;
}
I also suggest you'll have a look at React's functional approach with hooks https://reactjs.org/docs/hooks-intro.html, which makes all this a whole lot less fiddly, in my opinion. But it might take a bit to get used to.
u can pass functions like ur handler over the prop to childrens and update so from a child to the mother of the children, in the children u give the value the prop u supply from mother
<Select dataFeld="broker" id="yourid" value={this.state.brokerSel} ownonChange={(e) => this.setState({statename: e})

Get value from input component and use it in another component in React

I'm new to React and have this simple code example where I simply need to take value from input and show the value back.
class App extends React.Component {
constructor(props){
super(props);
this.state = { word : ""};
this.onClick = this.onClick.bind(this);
}
onClick(e){
this.setState({word : /* how to obtain input value?? */});
}
render() {
return (
<>
<form>
<input type="text"/>
<button onClick={this.onClick}>Say it!</button>
</form>
<div>
{this.state.word}
</div>
</>
);
}
}
I know react want's me to use component state as a way to propagate information from parent component to it's children. What I don't know is how I should obtain state of a children to be used in another children.
I believe this should be doable in react in simple manner as the equivalent way of doing it using pure DOM or JQuery would also be very simple (one or two lines of code).
You can use createRef
import React, { createRef } from "react";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { word: "" };
this.onClick = this.onClick.bind(this);
}
textInput = createRef();
onClick(e) {
this.setState({ word: this.textInput.current.value });
}
render() {
return (
<div className="App">
<form>
<input ref={this.textInput} type="text" />
<button onClick={this.onClick} type="button">
Say it!
</button>
</form>
<div>{this.state.word}</div>
</div>
);
}
}
export default App;
check here CodeSandBox
A few things here. First I don't see children as you mention. Moreover, you say obtain state of a children to be used in another children. You have just one parent component here. Then, you are using a <form> which means a button inside will submit the values so you need the escape hatch of e.preventDefault(). Finally, if you must use a class based component instead of functional component, you don't need any more constructor and you can bind your functions with an arrow function. Here is a working example of what I presume you are asking: https://codesandbox.io/s/sleepy-minsky-giyhk

react way of setting focus on a particular button in stateful component?

I tried different ways of setting focus to button on pageload like ref ,but it doesnt work. Thats is whenever pageloads focus should be on this button.
Can anyone help me with a sample example
class SubPageHeader extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
render() {
return (
<input type="button"/>
);
};
}
Can anyone help me with a solution ?
componentDidMount will execute only once when your page loads first time, to maintain a focus on every re-render you also need to use componentDidUpdate.
class SubPageHeader extends React.Component {
constructor(props) {
super(props);
this.myInput = React.createRef();
}
componentDidMount() {
this.myInput.current.focus(); //To focus first time page loads
}
componentDidUpdate(){
this.myInput.current.focus(); //To focus on every re-render
}
render() {
return (
<input type="button" ref={this.myInput} />
);
};
}
Using refs:
class Component extends React.Component{
input = React.createRef()
componentDidMount(){
this.input.current.focus()
}
render(){ return <input ref={this.input} /> }
}
Or plain HTML : <input autoFocus />
To focus on component mount the simplest way is
class SubPageHeader extends React.Component {
render() {
return (
<input autoFocus type="button"/>
);
};
}

want to pass values to parent component from child then wana get those value into another child component

this is my parent component
class App extends Component {
constructor()
{
super();
this.state={counter:1,yourid:'',yourname:'',yourgender:''};
this.handleLogin=this.handleLogin.bind(this);
this.userview=this.userview.bind(this);
this.going=this.going.bind(this);
}
going(id,name,gender)
{
console.log("THIS IS DONE BY REACT GEEK:",id,name,gender);
this.setState({yourid:id,
Yourname:name,
Yourgender:gender});
}
this is my app.js render funtion
<Login passingvalue={this.going} />
<MessageView LoggedInUser={this.going} />
and here is my first child components from where i send values
export default class Login extends Component {
constructor(props)
{
super(props);
this.state={
id:'',name:'',gender:''
}
this.show = this.show.bind(this);
this.sendingvalue=this.sendingvalue.bind(this)
}
sendingvalue()
{
this.props.passingvalue(this.state.id,this.state.name,this.state.gender);
// console.log('passing',Id);
console.log('hello this is going ',
this.state.id,
this.state.name,
this.state.gender)
}
and again here is my second child component where i want these values
export default class Messageonline extends Component {
constructor(props)
{
super(props);
this.state = {Id:this.props.LoggedInUser.yourid,
Name:this.props.LoggedInUser.yourname,
Gender:this.props.LoggedInUser.yourgender};
}
render() {
return (
<div className="messageshow">
<div className="row">
<div className="col-lg-10 "id="message_show">
<h3>Inbox</h3>
</div>
<div className="col-lg-2" id="online_user" >
<h3>online Users</h3>
<span>{this.state.Id}</span>
<br/>
<span>{this.state.Name}</span>
<br/>
<span>{this.state.Gender}</span>
</div>
</div >
</div>
there is any mistake thats why i cannot get those values in my second child..whats is that mistake i dont know ..tell me whats this mistake i want to fix that as soon as possible..thanks
Looks like you are passing the going method as the LoggedInUser prop to your MessageView component:
<MessageView LoggedInUser={this.going} />
You are probably looking to pass a user object instead.
Something like this:
<MessageView LoggedInUser={{
yourid: this.state.yourid,
yourname: this.state.yourname,
yourgender: this.state.yourgender
}} />

What is the purpose of this.props.onChange()?

From the react quickstart: https://facebook.github.io/react/docs/lifting-state-up.html
The purpose of the line:
handleChange(e) {
this.props.onChange(e.target.value);
}
was never explained and I can't figure out what it does. Is onChange a built in method of props? I thought props was simply just parameters for components, why can it invoke functions?
I came here with the same question, but I understand it now (at least I think I do). The issue is that onChange in the Calculator class is a prop, but in the render portion of the class TemperatureInput, it's an event listener. Sometimes I see this in React, where the same name is used on two completely different things, and I find it can easily create confusion. Here's what happens in the following code block:
class TemperatureInput extends React.Component {
handleChange(e) {
this.props.onChange(e.target.value); **(2)**
}
render() {
return (
<fieldset>
<input value={value} onChange={this.handleChange} /> **(3)**
</fieldset>
);
}
}
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
onChange={this.handleCelsiusChange} /> **(1)**
</div>
);
}
}
In Calculator, a made up prop called onChange passes a reference to the method handleCelsiusChange to TemperatureInput
this.props.onChange() in TemperatureInput is now a reference to handleCelsiusChange() in Calculator
onChange={this.handleChange} is an event listener, which will fire handleChange() up on the change of the input field.
In conclusion, onChange as a prop is custom, onChange as an event listener is built in. The prop just passes a function reference from an ancestor to the child so you can run it in the child.
I thought props was simply just parameters for components, why can it invoke functions?
You're right, but those parameters can also be callbacks/functions. E.g:
Definition:
class Comp extends Component {
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (<input onChange={this.handleChange.bind(this)) />
}
}
Usage:
<Comp onChange={(a) => console.log(a)} />
Got a clue from SeattleFrey's answer, maybe the author of that code shouldn't name this parameter onchange. It is so confusing for a starter of ReactJs like me.
I name it myChange instead of onChange. It is actually a function passed in as a parameter. And e.target.value is the parameter for that function.Props can contain objects as well as functions, since functions are also objects in Javascript
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.myChange(e.target.value);
}
render() {
const value = this.props.value;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={value}
onChange={this.handleChange} />
</fieldset>
);
}
}
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
myChange={this.handleCelsiusChange} />
</div>
);
}
}
You just missed this sentence:
If several components need access to the same state, it is a sign that the state should be lifted up to their closest common ancestor instead. In our case, this is the Calculator.
Your quoted code is from component TemperatureInput:
class TemperatureInput extends React.Component {
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (
<fieldset>
<input value={value} onChange={this.handleChange} />
</fieldset>
);
}
}
And TemperatureInput is a child component of Calculator, where TemperatureInput.onChange is assigned to Calculator. handleCelsiusChange
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
onChange={this.handleCelsiusChange} />
</div>
);
}
}

Resources