0

I am trying to create a simple SPA (without Router). It has also a simple structure: a component per section:

  • Home
  • Services
  • Products
    • Product
    • Modal
  • Contact us

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"):

Modal

That function should "change the state" of Contact us component (a simple contact us form):

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:

How to

I was reading this similar question but I didn't get how to apply in my scenario. Any ideas?

Maramal
  • 1,913
  • 2
  • 24
  • 58

3 Answers3

1

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.

Wael Zoaiter
  • 549
  • 4
  • 7
1

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.

  1. The easiest way is you can transfer subject via URL (URL is "the intermediary thing"). When you click the button Presupuestar you can change URL to page contact like this:

/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.

  1. The second way is creating a service use singleton pattern to transfer subject from Modal to Contact form. You can see my example.
Max
  • 428
  • 3
  • 9
0

You can achieve this like this

  • Create a main app component which will contain all these these three comps
  • Add a function in app component "changeContacts"
  • Send it to both the product as well as contacts
  • Here is an explanation
    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> );
        }
    }
    
    Maheer Ali
    • 32,967
    • 5
    • 31
    • 51