Reputation: 3465
I am trying to create a simple SPA (without Router). It has also a simple structure: a component per section:
As you can see the component Products has two sub-components Product and Modal. These are iterated so many times as JSON objects there are:
Products.js
import React, { Component } from "react";
import ReactHtmlParser from "react-html-parser";
import "./Products.css";
import { products } from "./products.json";
import Product from "./Product/Product";
import Modal from "./Modal/Modal";
class Products extends Component {
render() {
return (
<section id='products'>
<div className='container'>
<div className='row'>
{products.map(product => {
return (
<div>
<Product
image={"/img/" + product.image}
name={product.name}
target={product.target}
/>
<Modal
id={product.target}
title={product.name}
body={ReactHtmlParser(product.body)}
/>
</div>
);
})}
</div>
</div>
</section>
);
}
}
export default Products;
Each product has a More Info button what opens the modal and this has another button Budget ("Presupuestar"):
That function should "change the state" of Contact us component (a simple contact us form):
The component has the following code:
Contact.js
import React, { Component } from "react";
import "./Contact.css";
class Contact extends Component {
constructor() {
super();
this.state = { budget: "Contact" };
}
render() {
return (
<section id='contact'>
<div className='container'>
<div className='row'>
<div className='col-xs-12 col-md-6'>
<div className='contact-form'>
<form>
...
{/* Subject */}
<div className='form-group'>
<div className='input-group'>
<span className='input-group-addon' />
<input
type='text'
className='form-control'
id='subject'
aria-describedby='Subject'
placeholder='Subject'
readonly='readonly'
value={this.state.budget}
/>
</div>
{/* /form-group */}
</div>
{/* /Subject */}
...
</form>
</div>
</div>
</div>
</div>
</section>
);
}
}
I guess then I should create a function in the Modal component to trigger with an onClick="setSubject"
in the Budget ("Presupuestar") button. What I don't know is how to alter the other component's state.
A quick summary: I have to make the following state update:
I was reading this similar question but I didn't get how to apply in my scenario. Any ideas?
Upvotes: 0
Views: 123
Reputation: 458
First of all, you don't need a function to change the state
of another component. The smart way to do that is using an intermediary thing to connect 2 component together. There is two way to solve this problem.
/contact?subject=whatever you want
Then, at Contact component, you just need to parse URL to get subject (you can see this question to know how to parse from URL). You can see my example.
Upvotes: 1
Reputation: 36574
You can achieve this like this
class App extends Component {
render() {
return (
<div>
<Contact ref="contacts"/>
<Products changeContacts={this.changeContacts} />
</div>
);
}
changeContacts = (newState) => {
this.refs.contacts.changeState(newState)
};
}
class Contact extends Component {
state = { text:"Old Text" }
render() {
return ( <div style={{fontSize:50,backgroundColor:'red'}}>{this.state.text}</div> );
}
changeState = (newState) =>{
this.setState(newState);
}
}
class Modal extends Component {
render() {
return ( <div onClick={() => this.props.onClick({text:"New State Text"})}>This is a modal</div> );
}
}
class Products extends Component {
state = { }
render() {
return ( <div>
<h1>Products List</h1>
<Modal onClick={this.props.changeContacts} />
<Modal onClick={this.props.changeContacts}/>
<Modal onClick={this.props.changeContacts}/>
</div> );
}
}
Upvotes: 0
Reputation: 716
I think you should either but the clickHandler
function of the button in the App
component that wrap the whole components and then pass it to the Products
component then to Modal
component but it's not a good practice,
Or you can use Redux a state management system that let you control your state through the whole app.
Upvotes: 1