最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React click on item to show details - Stack Overflow

programmeradmin5浏览0评论

Iam new to React and I'm trying to interact with the swapi API. I want to get the list of films (movie titles list) and when I click on a title to show the opening_crawl from the json object. I managed to get the film titles in an array. I don't know how to proceed from here.

Here is my code:

class StarWarsApp extends React.Component {
  render() {
    const title = "Star Wars";
    const subtitle = "Movies";
    return (
      <div>
        <Header title={title} />
        <Movies />
      </div>
    );
  }
}

class Header extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
      </div>
    );
  }
}

class Movies extends React.Component {
  constructor(props) {
    super(props);
    this.handleMovies = this.handleMovies.bind(this);
    this.state = {
      movies: []
    };
    this.handleMovies();
  }

  handleMovies() {
    fetch("")
      .then(results => {
        return results.json();
      })
      .then(data => {
        console.log(data);
        let movies = data.results.map(movie => {
          return <div key={movie.episode_id}>{movie.title}</div>;
        });

        this.setState(() => {
          return {
            movies: movies
          };
        });
      });
  }
  render() {
    return (
      <div>
        <h1>Episodes</h1>
        <div>{this.state.movies}</div>
      </div>
    );
  }
}

ReactDOM.render(<StarWarsApp />, document.getElementById("app"));

Iam new to React and I'm trying to interact with the swapi API. I want to get the list of films (movie titles list) and when I click on a title to show the opening_crawl from the json object. I managed to get the film titles in an array. I don't know how to proceed from here.

Here is my code:

class StarWarsApp extends React.Component {
  render() {
    const title = "Star Wars";
    const subtitle = "Movies";
    return (
      <div>
        <Header title={title} />
        <Movies />
      </div>
    );
  }
}

class Header extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
      </div>
    );
  }
}

class Movies extends React.Component {
  constructor(props) {
    super(props);
    this.handleMovies = this.handleMovies.bind(this);
    this.state = {
      movies: []
    };
    this.handleMovies();
  }

  handleMovies() {
    fetch("https://swapi.co/api/films")
      .then(results => {
        return results.json();
      })
      .then(data => {
        console.log(data);
        let movies = data.results.map(movie => {
          return <div key={movie.episode_id}>{movie.title}</div>;
        });

        this.setState(() => {
          return {
            movies: movies
          };
        });
      });
  }
  render() {
    return (
      <div>
        <h1>Episodes</h1>
        <div>{this.state.movies}</div>
      </div>
    );
  }
}

ReactDOM.render(<StarWarsApp />, document.getElementById("app"));
Share Improve this question edited Dec 1, 2018 at 13:33 devserkan 17.7k4 gold badges33 silver badges48 bronze badges asked Dec 1, 2018 at 12:20 DanaeDanae 1411 gold badge5 silver badges13 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

To iterate over movies add this in render method:

render(){
  return (
    <div>
      <h1>Episodes</h1>
      {
        this.state.movies.map((movie, i) => {
          return (
            <div className="movie" onClick={this.handleClick} key={i}>{movie.title}
              <div className="opening">{movie.opening_crawl}</div>
            </div>
          );
        })
      }
    </div>
  );
}

Add this method to your Movies ponent to add active class on click to DIV with "movie" className:

handleClick = event => {
  event.currentTarget.classList.toggle('active');
}

Include this css to your project:

.movie .opening {
  display: none;
}

.active .opening {
  display: block
}

After fetching the data, just keep it in your state then use the pieces in your ponents or JSX. Don't return some JSX from your handleMovies method, just do the setState part there. Also, I suggest using a life-cycle method (or hooks API maybe if you use a functional ponent) to trigger the fetching. By the way, don't use class ponents unless you need a state or life-cycle methods.

After that, you can render your titles in your render method by mapping the movies state. Also, you can have a place for your opening_crawls part and render it with a conditional operator. This condition changes with a click. To do that you have an extra state property and keep the movie ids there. With the click, you can set the id value to true and show the crawls.

Here is a simple working example.

const StarWarsApp = () => {
  const title = "Star Wars";
  const subtitle = "Movies";
  return (
    <div>
      <Header title={title} />
      <Movies />
    </div>
  );
}

const Header = ({ title }) => (
  <div>
    <h1>{title}</h1>
  </div>
);

class Movies extends React.Component {
  state = {
    movies: [],
    showCrawl: {}
  };

  ponentDidMount() {
    this.handleMovies();
  }

  handleMovies = () =>
    fetch("https://swapi.co/api/films")
      .then(results => results.json())
      .then(data => this.setState({ movies: data.results }));

  handleCrawl = e => {
    const { id } = e.target;
    this.setState(current => ({
      showCrawl: { ...current.showCrawl, [id]: !current.showCrawl[id] }
    }));
  };

  render() {
    return (
      <div>
        <h1>Episodes</h1>
        <div>
          {this.state.movies.map(movie => (
            <div
              key={movie.episode_id}
              id={movie.episode_id}
              onClick={this.handleCrawl}
            >
              {movie.title}
              {this.state.showCrawl[movie.episode_id] && (
                <div style={{ border: "1px black solid" }}>
                  {movie.opening_crawl}
                </div>
              )}
            </div>
          ))}
        </div>
      </div>
    );
  }
}

ReactDOM.render(<StarWarsApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

I am using id on the target div to get it back from the event object. I don't like this method too much but for the sake of clarity, I used this. You can refactor it and create another ponent may be, then you can pass the epoisde_id there and handle the setState part. Or you can use a data attribute instead of id.

发布评论

评论列表(0)

  1. 暂无评论