将道具传递给新组件-ReactJS

时间:2018-09-16 20:19:05

标签: reactjs api browser router

想知道我是否能得到一些帮助。我正在构建一个工作板,并且正在使用github Jobs作为我的Jobs API feed。到目前为止,这是我的项目的codeandbox链接:

https://codesandbox.io/s/34kzz5k6k1 (您需要CORS chrome插件才能使api正常工作。)

基本上:

  1. 在index.js文件中,我将在“ ComponentDidMount”中调用API。
  2. 默认情况下,我的页面上会显示“纽约”的工作。
  3. 当您在“伦敦”中的“处理提交”中搜索“开发人员”工作时,您会看到我正在将结果推送到新的URL“ / jobresults”中。
  4. 我正在使用浏览器路由器执行此操作。

我遇到的问题。因此,我的默认作业仍显示在/ jobresults上。以及显示在下方的“伦敦”搜索结果。

如何仅使“伦敦”工作出现在此页面上?

我认为我可以尝试在所有前端构建工作板。但是现在我想我还需要在后端进行REST路由?

也许将我的API调用保存在数据库中。然后在“显示”路线上显示结果?

您能提供的任何指导都很棒!

谢谢。

1 个答案:

答案 0 :(得分:1)

这里有很多事情确实需要修改。构建应用程序的方式是反模式的(非标准/不好的做法),并且随着应用程序变得更加动态,将使您更加头疼。

我已经着手重组了整个应用程序。我鼓励您解构它并遵循应用程序流程,然后进行项目并进行相应的修复。

工作示例:https://codesandbox.io/s/v873j0600y(仍需要CORS扩展名)


index.js

import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import JobForm from "./components/JobForm";
import JobResults from "./components/JobResults";
import NavHeader from "./components/NavHeader";
import "uikit/dist/css/uikit.min.css";
import "./styles.css";

const App = () => (
  <main>
    <BrowserRouter>
      <section>
        <NavHeader />
        <Switch>
          <Route exact path="/" component={JobForm} />
          <Route path="/jobs" component={JobResults} />
          <Route path="/jobresults/:id" component={JobResults} />
        </Switch>
      </section>
    </BrowserRouter>
  </main>
);

render(<App />, document.getElementById("root"));

NavHeader.js

import React from "react";
import { Link } from "react-router-dom";

export default () => (
  <header>
    <nav>
      <ul style={{ listStyleType: "none" }}>
        <li style={{ display: "inline", marginRight: 20 }}>
          <Link to="/">Home</Link>
        </li>
        <li style={{ display: "inline", marginRight: 20 }}>
          <Link to="/jobs">Jobs</Link>
        </li>
      </ul>
    </nav>
  </header>
);

JobForm.js

import React, { Component } from "react";

export default class JobForm extends Component {
  state = { searchData: "", cityData: ""};

  // HANDCHANGE FOR JOB SEARCH
  handleChange = e => this.setState({ searchData: e.target.value });

  // HANDLE CHANGE FOR LOCATION SEARCH
  handleChangeLocation = e => this.setState({ cityData: e.target.value });

  // HANDLE SUBMIT
  handleSubmit = e => {
    e.preventDefault();
    const { cityData, searchData } = this.state;
    if (!cityData || !searchData) return;
    this.props.history.push(
      `/jobresults/positions?description=${searchData}&location=${cityData}`
    );
  };

  render = () => (
    <section className="hero homepage">
      <div className="container">
        <h1 className="title has-text-white">USA Creative City</h1>
        <h2 className="title has-text-white">Start your job search here!</h2>
        <form className="level-item" onSubmit={this.handleSubmit}>
          <div className="inputstyle field has-addons">
            <div className="control ">
              <input
                className="uk-input"
                type="text"
                placeholder="Software Engineer..."
                onChange={this.handleChange}
                style={{ width: 200 }}
              />
            </div>
            <div className="control ">
              <input
                className="uk-input"
                type="text"
                placeholder="City"
                onChange={this.handleChangeLocation}
                style={{ width: 200 }}
              />
            </div>
            <div className="control">
              <button
                style={{ width: 200 }}
                className="uk-button uk-button-primary"
              >
                <i
                  style={{ marginRight: 10 }}
                  className="fas fa-search"
                  aria-hidden="true"
                />Search Jobs
              </button>
            </div>
          </div>
        </form>
      </div>
    </section>
  );
}

JobResults.js

import isEmpty from "lodash/isEmpty";
import React, { Component, Fragment } from "react";
import axios from "axios";
import qs from "qs";
import Spinner from "./Spinner";
import ShowResults from "./ShowResults";
import NoResults from "./NoResults";

const getRandomInt = max => Math.floor(Math.random() * Math.floor(max));
const locations = ["Los Angeles", "New York", "San Mateo", "San Francisco"];
const descriptions = ["Developer", "Engineer", "MySQL", "MongoDB"];

export default class JobResults extends Component {
  state = { isLoading: true, jobs: [], error: "" };

  componentDidUpdate = (prevProps, prevState) => {
    if (this.props.location.pathname !== prevProps.location.pathname) {
      this.setState({ isLoading: true }, () => this.fetchData());
    }
  };

  componentDidMount = () => this.fetchData();

  fetchData = () => {
    let { description, location } = qs.parse(this.props.location.search, {
      ignoreQueryPrefix: true
    });

    if (!description || !location) {
      description = descriptions[getRandomInt(3)];
      location = locations[getRandomInt(3)];
    }

    axios(`https://jobs.github.com/positions.json?description=${description}&location=${location}`)
      .then(({ data }) => this.setState({ isLoading: false, jobs: data.slice(0, 9) }))
      .catch(err => this.setState({ isLoading: false, err: err.toString() }));
  };

  render = () =>
    this.state.isLoading 
     ? <Spinner />
     : <section>
        <h3 style={{ textAlign: "center" }} className="has-text-centered animated shake slow">
          RESULTS
        </h3>
        <div className="columns is-multiline">
          {isEmpty(this.state.jobs) 
            ? <NoResults err={this.state.err} />
            : <ShowResults jobs={this.state.jobs} />
          }
        </div>
      </section>
    );
}

ShowResults.js

import map from "lodash/map";
import React from "react";

export default ({ jobs }) => (
  map(jobs, ({ id, created_at, company_logo, title, company, location, url }) => (
      <div className="result" key={id}>
        <img className="image" src={company_logo} />
        <h4 className="has-text-left purple">Location: {title}</h4>
        <h5 className="has-text-left purple">
          Created on: {created_at}
        </h5>
        <h5 className="has-text-left purple">Company: {company}</h5>
        <h5 className="has-text-left purple">Location: {location}</h5>
        <a className="uk-button uk-button-primary" href={url} target="_new">
          apply on github
        </a>
        <a
          className="uk-button uk-button-primary"
          style={{ marginTop: 10 }}
          href={url}
          target="_new"
        >
          apply on creative jobs
        </a>
      </div>
    )
);

NoResults.js

import React from "react";

export default ({ err }) => (
  err 
    ? <p style={{ textAlign: "center", color: "red" }}>
        <i style={{ marginRight: 5 }} className="fas fa-exclamation-circle" /> 
        {err}
      </p>
    : <p style={{ textAlign: "center", color: "grey" }}>
        <i style={{ fontSize: 22, marginRight: 5 }} className="far fa-calendar-times"/>
        No jobs matching that criteria.
      </p>
);

Spinner.js

import React from "react";

const spinners = () => {
  let children = [];
  for (var i = 1; i < 13; i++) {
    children.push(<div key={i} className={`sk-circle${i} sk-circle`} />);
  }
  return children;
};

export default () => <div className="sk-fading-circle">{spinners()}</div>;