Search code examples
javascriptreactjsgetfetch-api

Get clicked ID from parent to child element with ReactJs


I'm developing an application in ReactJs and now I need to pass the clicked ID from Main.js page to Sofa.js, which will show different information depending in which ID you just clicked. I have my ming all formatted to PHP, I wish ReactJs had a global variable like $_GET ahah. Maybe it is, I just don't now. I've been searching and don't find what I'm looking for. I'll show the code below.
Main.js code with no imports included:

export class Main extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            token: {},
            isLoaded: false,
            models: [],
            offset: offset,
            limit: limit
        };
    }

    componentDidMount() {

        /* Some code not relevant to the question, for getting API token */

        fetch('url/couch-model?offset=' + offset + '&limit=' + limit, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': 'JWT ' + (JSON.parse(localStorage.getItem('token')).token)
            }
        }).then(res => {
            if (res.ok) {
                return res.json();
            } else {
                throw Error(res.statusText);
            }
        }).then(json => {
            this.setState({
                models: json.results,
                isLoaded: true
            }, () => { });
        })    
    }

    render() {

        const { isLoaded, models } = this.state;

        if (!isLoaded) {

            return (
                <div id="LoadText">
                    Loading...
                </div>
            )

        } else {

            return (
                <div>

                    {models.map(model =>
                        <a href={"/sofa?id=" + model.id} key={model.id}>
                            <div className="Parcelas">
                                <img src={"url" + model.image} className="ParcImage" alt="sofa" />
                                <h1>{model.name}</h1>

                                <p className="Features">{model.brand.name}</p>

                                <button className="Botao">
                                    <p className="MostraDepois">Ver Detalhes</p>
                                    <span>+</span>
                                </button>
                                <img src="../../img/points.svg" className="Decoration" alt="points" />
                            </div>
                        </a>
                    )}

                    <PageButtons offset={offset} />

                </div>
            )
        }
    }
}

As you can see the <a> inside the second return sends an ID, even though I'm not sure it's the right way. I tried writing is route-js the path like this /sofa/:id, but somehow, CSS inside /sofa/1 stopped working, whatever the ID was.

Now Sofa.js code, no imports and only relevant code:

export class Sofa extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            token: {},
            isLoaded: false,
            model: {}
        };
    }

    componentDidMount() {

        fetch(url + '/couch-model/1{/*this show be id clicked and sent by url*/}/', {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': 'JWT ' + (JSON.parse(localStorage.getItem('token')).token)
            }
        }).then(res => {
            if (res.ok) {
                return res.json();
            } else {
                throw Error(res.statusText);
            }
        }).then(json => {
            this.setState({
                model: json,
                isLoaded: true
            }, () => {});
        })
    }

    render() {

        const { model, isLoaded } = this.state;

        if (!isLoaded) {

            return (
                <div id="LoadText">
                    Estamos a preparar o seu sofá!
                </div>
            )

        } else {

            return (
                <div id="Esquerda">    
                    <h2>{model.area_set.map(area => area.name)}</h2>    
                    <h1>{model.name}</h1>
                    <p>Highly durable full-grain leather which is soft and has  a natural look and feel.</p>    
                    <h3>Design</h3>
                    <h4>Hexagon</h4>
                </div>
            );

        }

    }

}

Also, here's route.js:

const Routes = (props) => (
    <BrowserRouter>
        <Switch>
            <Route path='/sofa/:id' component={Sofa}/>
            <Route path='/home' component={Home}/>
            <Route path='*' component={NotFound}/>            
        </Switch>
    </BrowserRouter>
);

export default Routes;

Solution

  • I see you're not using (from what I can see from the example) react-router.

    I really recommend you using it because it makes situations like this super easy.

    Like in this example

    const ParamsExample = () => (
      <Router>
        <div>
          <h2>Accounts</h2>
          <ul>
            <li>
              <Link to="/netflix">Netflix</Link>
            </li>
            <li>
              <Link to="/zillow-group">Zillow Group</Link>
            </li>
            <li>
              <Link to="/yahoo">Yahoo</Link>
            </li>
            <li>
              <Link to="/modus-create">Modus Create</Link>
            </li>
          </ul>
    
          <Route path="/:id" component={Child} />
        </div>
      </Router>
    );
    

    And the Child component has match injected by the route.

    const Child = ({ match }) => (
      <div>
        <h3>ID: {match.params.id}</h3>
      </div>
    );
    

    Here is a CodeSandbox that you can play around with

    In your case Sofa is the Child component. You could call any API you want on componentDidMount with the id you received from the url.