I'm new to React and thus the question.
I have a parent Component - HomePage with a child Component - SideBar.
My child component sidebar needs to pass a data back to the parent on a submit button click which the parent needs to post on an api.
This my parent component,
class HomePage extends React.Component{
constructor(props) {
.......
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(){
//Logic to get the data from the child and post to localhost:8080/
}
render(){
return(
<div className="col-md-2 left-pane">
<Sidebar handleSubmitButton={this.state.handleSubmit}/>
</div>
);
}
}
This is my child component,
class Sidebar extends React.Component {
handleSubmitButton(event) {
event.preventDefault();
}
render() {
return (
<div>
<input type="text"/>
<button type="button" className="btn btn-info btn-icons" onClick={this.props.handleSubmitButton} >
<span className="glyphicon glyphicon-send" aria-hidden="true"/>
</button>
</div>
);
}
}
Sidebar.propTypes = {
handleSubmitButton: React.PropTypes.func
};
My question is how do I grab the input text with the onclick method on the sidebar button click and pass it up to the parent to post it on an api. Any help appreciated.
Your parent Component should not access the input directly, but rather rely on the child component to pass any values to the parent when required.
class HomePage extends React.Component {
constructor(props) {
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(textInputValue){
// The callback passed to the child component will
// submit the data back to it's parent.
// Logic to post to localhost:8080/
}
render(){
return(
<div className="col-md-2 left-pane">
<Sidebar handleSubmitButton={ this.handleSubmit }/>
</div>
);
}
}
class Sidebar extends React.Component {
constructor(props) {
this.handleSubmitButton = this.handleSubmitButton.bind(this);
}
handleSubmitButton(event) {
event.preventDefault();
// By giving the input the `ref` attribute, we can access it anywhere
const textInputValue = this.refs.input.value;
// Submit the value to the parent component
this.props.handleSubmitButton(textInputValue);
}
render() {
return (
<div>
<input type="text" ref="input" />
<button type="button" className="..." onClick={this.handleSubmitButton} >
<span className="glyphicon glyphicon-send" aria-hidden="true"/>
</button>
</div>
);
}
}
This prevents coupling your components together and will ease testing later.
In your child component you can create a property for the ref attribute. Accessing DOM elements directly is usually done by setting refs.
In your parent component you can use an arrow function with a callback which allows you to access the <input> DOM element anywhere within your parent component, by simply typing this.textInput
More information about refs can be found in the official React documentation: https://facebook.github.io/react/docs/refs-and-the-dom.html
Parent component:
handleSubmit() {
console.log(this.textInput.value);
}
<Sidebar
inputRef={(input) => this.textInput = input}
handleSubmitButton={this.state.handleSubmit}
/>
Child component:
<input ref={this.props.inputRef} type="text"/>
There's a couple ways you can go about it. One is you can add an onChange event to the input to update state of the Sidebar component. Then when the submit handler is clicked, pass the value from state, and have the HomePage handleSubmit() accept the value.
The other is to also pass an onChange prop from the HomePage component to the Sidebar. The input would then set the onChange to that prop.
Related
I am using the react-bootstrap Modal, Form and Button.
Desiring the functionality of clicking the button should open the modal with a form inside it. After filling out the form, one clicks a button (on the modal) and it validates the form data and posts it through a REST API.
I got far enough to figure out that my component split should be as follows:
A button component, a modal component and a form component.
What would be the correct way to structure these components in terms of props/state and placing the functions for validating the data? I am having trouble in understanding the child/parent relationship and when it's applicable
Components:
App Component: This is going to be the top level component
Button Component (If its just a button can also be
just a button):
If this is just a button you can keep this has a just a button in App component, if you are willing to reuse this with some custom element place it in a component.
Modal component: This is going to hold your modal like header,body,footer
Form component: This is a component which will hold the form and its validations.
Component Tree:
App Component will contain a state like showModal, we need to have a handler to set this value and this handler gets triggered when the button is clicked.
import FormModal from './FormModal';
class App extends React.Component {
state = {
showModal : false
}
showModalHandler = (event) =>{
this.setState({showModal:true});
}
hideModalHandler = (event) =>{
this.setState({showModal:false});
}
render() {
return (
<div className="shopping-list">
<button type="button" onClick={this.showModalHandler}>Click Me!
</button>
</div>
<FormModal showModal={this.sate.showModal} hideModalHandler={this.hideModalHandler}></FormModal>
);
}
}
Form Modal:
import FormContent from './FormContent';
class FormModal extends React.Component {
render() {
const formContent = <FormContent></FormContent>;
const modal = this.props.showModal ? <div>{formContent}</div> : null;
return (
<div>
{modal}
</div>
);
}
}
export default FormModal;
Hope that helped!
For basic pseudo code
Main Component:
import Modal from './Modal'
class Super extends React.Component {
constructor(){
this.state={
modalShowToggle: false
}
}
ModalPopUpHandler=()=>{
this.setState({
modalShowToggle: !modalShowToggle
})
}
render(){
return(){
<div>
<Button title='ModalOpen' onClick='this.ModalPopUpHandler'> </Button>
<ModalComponent show={this.state.modalShowToggle}>
</div>
}
}
}
ModalPopUp component:
import FormComponent from 'FormComponent'
class ModalComponent extends React.Component {
constructor(props){
super(props)
this.state={
modalToggle: props.show
}
}
render(){
if(this.state.modalToggle){
return(
<div>
<div className='ModalContainer'>
<FormComponent />
</div>
</div>
)
} else {
</div>
}
}
}
Form Component:
import Button from './Button'
class FormComponent extends React.Component {
constructor(){
this.state={
submitButtonToggle: true,
username: ''
}
}
inputHandler=(e)=>{
if(e){
this.setState({
username: e.target.value
})
}
}
render(){
return(
<div>
<input type='text' value='this.state.username' id='username' onChange='inputHandler' />
<Button title='Submit' disabled={this.state.username.length > 0}> </Button>
</div>
)
}
}
Above are the basic superComponent which we have rendered in app/main entry file.
And form || Modal Component. are the child component.
So in modal component I have called the same Form-component.
Here in Form-component input type handler, submit button is disabled from state.. with input string length we are handling its validation.
I hope it works for you.
I have seen similar questions to this but they are usually talking about a parent accessing a child component's methods or passing in methods through props. My question is on a specific situation, using props.children, and having any child component be able to call a method on the parent that is rendering props.children.
A simplified example of what im trying to achieve:
class WrapperComponent extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this)
}
handleInputChange(e){
console.log("neat, you changed the input")
}
render() {
return (
<form>
{this.props.children}
</form>
)
}
}
And the component that is calling said component and passing in the children as props.
const Component = (props) => {
return(
<WrapperComponent>
<div className="form-group" >
<label>
<div>Text</div>
<input onChange={this.handleInputChange} type={"text"}/>
</label>
</div>
</WrapperComponent>
)
}
The idea is that I can render a component that holds certain logic, and pass in the elements as children for that component to render, but also that the props.children can then call said logic within the wrapper, so I can pass in different children in different use cases, but the handling will always be the same. Is there a way to do this at all?
You can clone your elements and add new props to them using some built-in React goodies:
class WrapperComponent extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this)
}
handleInputChange(e){
console.log("neat, you changed the input")
}
render() {
return (
<form>
{React.Children.map(
this.props.children,
el => React.cloneElement(el, {onInputChange: this.handleInputChange})
)}
</form>
)
}
}
Then (remove WrapperComponent):
const Component = (props) => {
return(
<div className="form-group" >
<label>
<div>Text</div>
<input onChange={props.onInputChange} type={"text"}/>
</label>
</div>
)
}
Then:
ReactDOM.render(
<WrapperComponent><Component /></WrapperComponent>,
document.getElementById('root')
)
Yes, there's a way, but its not straightforward, and you may want to consider a different approach.
In order for a child component to have access to the methods of an arbitrary parent, the parent must override the child's props. This can be done using React.cloneElement in the render() function of the parent. In your example:
class WrapperComponent extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this)
}
handleInputChange(e){
console.log("neat, you changed the input")
}
render() {
return (
<form>
{React.Children.map(this.props.children, child => (
React.cloneElement(child, {handleInputChange: this.handleInputChange}
)}
</form>
)
}
}
Then, you can access the method in the child via this.props.handleInputChange.
I have Main Component file and use in another child component.
I have to get state of the child component.
Ex :- Home (Parent)
- Form (Child) component i have been set the value of any text box in state. So ho can i get the state value of Form component into the main component.
Generally in React (and React-Native) information is passed down from the parent component to its children. However if you need to change something in the parent component's state based on the child-component's state, you can pass a function to the child that does just that.
For example:
// Inside Parent Component
openModalFromParent() {
this.setState({ modalOpened: true });
};
// Passing Function to Child
<ChildComponent openModal={ this.openModalFromParent } />
// Inside Child Component
<TouchableHighlight onPress={ () => this.props.openModal() } />
In this example the button in the child component would trigger a function that alters the state of the parent component - hope this helps!
Pass the function as a prop to the child component
//Parent Component
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
};
this._handleChange = this._handleChange.bind(this);
}
_handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value
});
}
render(){
return(){
<Form valueChange={this._handleChange} />
}
}
}
//Child Component
export default class Form extends Component {
render(){
return(){
<div>
<input type="email" name="username" onChange={(e) => this.props.valueChange()} value={username}/>
<input type="password" name="password" onChange={(e) => this.props.valueChange()} value={password}/>
</div>
}
}
}
In React, your state can only flow down from the parent to the children.
What you should do is move the state from the child to the parent and then pass the state to the child as props.
Try reading this: https://reactjs.org/docs/lifting-state-up.html
I am trying to add a className to a child component of layouts/index.js in React with Gatsby. How can I pass the className in props to be used with the component when the onClick is registered in another component?
index.js
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
navIsVisible: false,
}
this.handleNavIsVisible = this.handleNavIsVisible.bind(this)
}
handleNavIsVisible() {
this.setState({
navIsVisible: !this.state.navIsVisible
})
}
render() {
const { children } = this.props
return (
<div>
<MenuButton navIsVisible={this.handleNavIsVisible}/>
<div className="page">
...
</div>
{/* Adding the class here seems to be the best option but does not activate onClick, yet does if adding to a div with Menu contained */}
<Menu className={`${this.state.navIsVisible ? 'nav-is-visible' : ''}`}/>
</div>
)
}
}
MenuButton.js to activate the class onClick
class MenuButton extends Component {
constructor(props) {
super(props)
this.menuClick = this.menuClick.bind(this)
}
menuClick(){
this.props.navIsVisible();
}
render () {
return (
<div className="sticky-menu-button">
<span onClick={this.menuClick}>Menu</span>
</div>
)
}
}
MenuButton.propTypes = {
navIsVisible: PropTypes.func,
}
Alternatively, within Menu.js but unsure how to pass the state change to this component?
The reason it works on a div and not on your Menu component is that when you pass it to a div it adds that class "directly" to the div HTML element but when you pass it to your component it just passes it as a prop. It really depends on what you do inside the render method of the Menu component and what you return from it. If you make sure to grab that prop and attach it to whatever it renders it will work just as it did on a div.
eg:
class Menu extends Component {
render () {
return (
<div className={this.props.className}>
<p> Menu Component </p>
</div>
)
}
}
My React app has several similar custom buttons that perform different tasks. The UI is similar among all the buttons, what changes is the action each one must trigger and the title.
The working code for the parent Component containing the buttons is (similar) to the following:
class Page extends Component {
constructor(props) {
super(props);
}
action1(){
//... do stuff...
}
action2(){
//... do stuff...
}
render(){
return(
<div className="table-row">
<div className="table-cell">
<div className="button"
onClick={this.action1.bind(this)}>{"button1"}
</div>
</div>
<div className="table-cell">
<div className="button"
onClick={this.action2.bind(this)}>{"button2"}
</div>
</div>
</div>
);
}
}
Is it possible to pass a method to the child component the same way it is done for a variable value? I want to turn it into something like this:
class Page extends Component {
constructor(props) {
super(props);
}
action1(){
//... do stuff...
}
action2(){
//... do stuff...
}
render(){
return(
<div className="table-row">
<div className="table-cell">
<CustomButton action={this.action1.bind(this)} title={"button1"}/>
</div>
<div className="table-cell">
<CustomButton action={this.action2.bind(this)} title={"button2"}/>
</div>
</div>
);
}
}
class CustomButton extends Component{
constructor(props){
super(props);
}
render() {
return (
<div className="table-cell"><div className="button"
onClick= {this.props.action}>{this.props.title}
</div>
);
}
}
What would be the correct way to handle this situation and the theory behind it?
I'm using React with Meteor, in case it makes a difference.
You can pass props to components. Passed props can have any data type of javascript.
In your case, you want to pass an action props which has a function as the value. Then you access action props in your component and use it.
In short, there is no theory behind it. What you are doing is correct. This is how react handles passing data to other components. Note that this is not the only way to pass data to child components.