1

I have just started learning React and I'm trying to make a simple application for searching vacancies using third-party server API. The application consists of form with one input, on submit it sends a request to server using axios, gets a response and must render it.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import "bootstrap/dist/css/bootstrap.css";
import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://api.hh.ru/vacancies/',
  headers: {
        'User-Agent': 'React App/1.0 (tatyana.fomina.1986@gmail.com)', 
        'HH-User-Agent': 'React App/1.0 (tatyana.fomina.1986@gmail.com)'
    }
});

const Header = () => {
    return <h1>Поиск вакансий на HH.ru</h1>
}

const Vacancies = props => {
    return <div>Some Text</div>
}

class SearchForm extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            position: ''
        }

        this.handlePositionChange = this.handlePositionChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handlePositionChange(e) {
            this.setState({
                [e.target.name]: e.target.value
            });
        }

    handleSubmit(e) {
        e.preventDefault();

        var formButton = document.getElementById('form-button');
        formButton.disabled = true;

        var position = this.state.position;
        console.log(position);

        if ( position ) {
            instance({
                    method: 'GET',
                    url: '?text=' + position,
                    data: {
                        position: position
                    }
                })
                .then(function(response) {
                    console.log(response.data);
                    formButton.disabled = false;
            })
               .catch(function (error) {
                console.log(error);
              });
        } else {
            formButton.disabled = false;
        }
    }

    render() {
        return (
            <form className="form search-form" onSubmit = { this.handleSubmit }>
                <div className="form-row">
                    <div className="form-group col-md-8">
                        <label htmlFor="position"> Position *
                            < /label>
                                <input type="text" className="form-control" name="position" id="position" placeholder="Position" onChange={ this.handlePositionChange } value={ this.state.position } />
                    </div>

                    <div className="form-group col-md-4 d-flex flex-column justify-content-end">
                        <input id = 'form-button'
                        className = 'btn btn-primary'
                        type = 'submit'
                        placeholder = 'Send' / >
                    </div>
                </div>
            </form>
        )
    }
}

class App extends Component {
  render() {
    return (
      <div className="container">
        <div className="row">
            <div className="col-12">
                <Header />
                <SearchForm />
                <Vacancies />
            </div>
        </div>
      </div>
    );
  }
}

export default App;

I have a problem with rendering <Vacancies />, is it possible to render it dynamically and update data every time on every new request and response from server?

Heidel
  • 3,174
  • 16
  • 52
  • 84

1 Answers1

2

What you want is for Vacancies to get the updated data which is what you get after an API request from SearchForm, in such a case you need to restructure your components and Lift the action up in the parent and pass the data as props to the Sibling components

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import "bootstrap/dist/css/bootstrap.css";
import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://api.hh.ru/vacancies/',
  headers: {
        'User-Agent': 'React App/1.0 (tatyana.fomina.1986@gmail.com)', 
        'HH-User-Agent': 'React App/1.0 (tatyana.fomina.1986@gmail.com)'
    }
});

const Header = () => {
    return <h1>Поиск вакансий на HH.ru</h1>
}

const Vacancies = props => {
    return <div>Some Text</div>
}

class SearchForm extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            position: ''
        }

        this.handlePositionChange = this.handlePositionChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handlePositionChange(e) {
            this.setState({
                [e.target.name]: e.target.value
            });
        }

    render() {
        return (
            <form className="form search-form" onSubmit = { (e) => this.handleSubmit(e, this.state.position) }>
                <div className="form-row">
                    <div className="form-group col-md-8">
                        <label htmlFor="position"> Position *
                            < /label>
                                <input type="text" className="form-control" name="position" id="position" placeholder="Position" onChange={ this.handlePositionChange } value={ this.state.position } />
                    </div>

                    <div className="form-group col-md-4 d-flex flex-column justify-content-end">
                        <input id = 'form-button'
                        className = 'btn btn-primary'
                        type = 'submit'
                        disabled={this.props.disableSubmit}
                        placeholder = 'Send' / >
                    </div>
                </div>
            </form>
        )
    }
}

class App extends Component {
      state = {
        disableSubmit: false;
      }
      handleSubmit = (e, position) => {
        e.preventDefault();

        this.setState({disableSubmit : true});
        console.log(position);

        if ( position ) {
            instance({
                    method: 'GET',
                    url: '?text=' + position,
                    data: {
                        position: position
                    }
                })
                .then(function(response) {
                    this.setState({data: response.data, disableSubmit:false});
            })
               .catch(function (error) {
                console.log(error);
              });
        } else {
            this.setState({disableSubmit : false});
        }
    }
  render() {
    return (
      <div className="container">
        <div className="row">
            <div className="col-12">
                <Header />
                <SearchForm handleSubmit = {this.handleSubmit} disableSubmit={this.state.disableSubmit}/>
                <Vacancies data={this.state.data}/>
            </div>
        </div>
      </div>
    );
  }
}

export default App;

Also while using React you must make sure that you are not modifying the DOM element yourself and handle all Interactions the React way. For instance you can control the disabled state of your submit button using a prop or a state.

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • It's hard to understand for me, why the component can't contain all its logic itself and why logic must be placed in component's parent. I used to OOP classes with all their data and logic inside. But anyway thanks for explanation! – Heidel Apr 02 '18 at 10:09
  • @Heidel, I think react docs are a good place to know how to handle different scenarios, for a start you could look at https://reactjs.org/docs/lifting-state-up.html. Also check this answer https://stackoverflow.com/questions/46594900/reactjs-lifting-state-up-vs-keeping-a-local-state/47349693#47349693 – Shubham Khatri Apr 02 '18 at 10:11