如何让组件根据用户在单独组件中单击的链接显示不同的内容?

时间:2018-05-31 04:23:28

标签: javascript reactjs redux react-router http-get

我有一个组件,显示从Movies API生成的电影类型列表。我想要的是,当用户点击特定类型时,它会显示指定类型的电影。

我的问题是,我能想到这样做的唯一方法是为每个类型创建一个不同的组件,为我的Redux中的每个类型创建一个不同的动作创建者,为每个类型的API执行GET请求,并为指定的流派设置指向该组件的链接。这似乎非常耗时且效率低下。

有没有办法让ShowGenres组件显示不同的电影,具体取决于用户在Genre组件中点击的类型,还是我认为唯一的解决方案?

这是我的Redux:

import {createStore, applyMiddleware} from "redux";
import axios from "axios";
import thunk from "redux-thunk";

export const displayGenres = () => {
    return dispatch => {
        axios.get("https://api.themoviedb.org/3/genre/movie/list?api_key=<api-key>&language=en-US").then(response => {
            dispatch({
                type: "DISPLAY_GENRES",
                genres: response.data.genres
            })
        }).catch(err => {
            console.log(err);
        })
    }
}

export const selectedGenre = id => {
    return dispatch => {
        axios.get(`https://api.themoviedb.org/3/discover/movie?api_key=<api-key>&language=en-US&include_adult=false&include_video=false&page=1&primary_release_year=2017&with_genres=9648`).then(response => {
            dispatch({
                type:"SELECTED_GENRE",
                select: response.data.results
            })
        }).catch(err => {
            console.log(err);
        })
    }
}

const reducer = (prevState = {}, action) => {
    switch(action.type){
        case "DISPLAY_GENRES":
            return {
                genres: action.genres
            }
        case "SELECTED_GENRE":
            return {
                select: action.select,
            }
        default:
            return prevState
        }
    }

const store = createStore(reducer, applyMiddleware(thunk));

export default store;

这是我的Genres组件,显示所有单个类型供用户选择:

import React, {Component} from "react";
import {connect} from "react-redux";
import {displayGenres} from "./redux";
import {Link} from "react-router-dom";
import Navbar from "./Navbar";

class Genres extends Component {
    constructor(){
        super();
    }

    componentDidMount(){
        this.props.displayGenres();
    }

    render(){

        const mappedGenres = this.props.genres && this.props.genres.map(genre => {
            return (
                    <div className="mappedGenres">
                        <Link to="/showGenres">{genre.name}</Link>
                    </div>    
            )
        })
        return(
            <div>
                <Navbar/>
                <div className="genre">
                    {mappedGenres}
                </div>
            </div>

        )
    }
}

export default connect(state => state, {displayGenres})(Genres);

这是我的ShowGenres组件,我想根据用户在Genre组件中点击的类型来显示电影:

import React, {Component} from "react";
import {connect} from "react-redux";
import {selectedGenre} from "./redux";
import {displayGenres} from "./redux";


class ShowGenres extends Component {
    constructor(){
        super();
    }

    componentDidMount(){
        this.props.selectedGenre(this.mappedId);
    }

    render(){

        const mappedId = this.props.genres && this.props.genres.map(id => {
            return id.id;
        })

        const mappedSelected = this.props.select && this.props.select.map(genre => {
            return (
                <div>
                    <h1>{genre.title}</h1>
                </div>
            )
        })

        return(
            <div>
                {mappedSelected}
            </div>
        )
    }
}

export default connect(state=> state, {displayGenres, selectedGenre})(ShowGenres);

2 个答案:

答案 0 :(得分:0)

你可以这样做的一种方法是使用一个接受输入的方法并用所述输入设置状态。现在你从这里开始的地方可能会有所不同。

您可以将第二个组件嵌套在第一个组件中,将该方法作为道具传递,并为每个电影添加一个点击事件监听器,从道具中触发该方法,将您单击的电影类型作为参数传递。该方法必须绑定到父级才能传递给子级

会写一个例子并很快发布。

答案 1 :(得分:0)

这是一个例子。某处有一个小错误,但总的想法就在那里。我以前用过它,但是自从触摸反应已近一年了。原谅邋。

const AllMovies = {
  Horror : ['Tax Season', 'Family Dinner', 'DMV Trip 3'],
  Comedy : ['Pasion of the Christ', 'The Earth is Flat'],
  Romance : ['Me, Myself and Bacon', 'There\'s Something About Ice Cream']
}

class Movie
  {
    constructor(title, genre)
    {
      this.genre = genre;
      this.title = title;
    }
  }

class ChildContainer extends React.Component
{
  constructor(props)
  {
    super(props);

  }
  
  GenerateList()
  {
    let output = [];
    for (var genre in AllMovies)
    {
      let movies = AllMovies[genre];
      for (let i = 0; i < movies.length; i++)
      {
        output.push(new Movie(movies[i], genre))
      }
      
    }
    return output.map(movie => {
      return(
        <li onClick={() => this.props.CallParent(movie.genre)}>
          {movie}
       </li>
          )
    })
  }
  
  render()
  {
    return(
      <ul>
        {this.GenerateList()}
      </ul>
    )
  }
}


class ParentContainer extends React.Component
{
  constructor(props)
  {
    super(props);
    
    this.state = {
      CurrentValue : []
    }
    
    this.PropMethod = this.PropMethod.bind(this);
  }
  
  PropMethod(newValue)
  {
    console.log('__GENRE__ : ', newValue);
    let genre = AllMovies[newValue]
    this.setState({
      CurrentValue : genre
    })
  }
  
  render() {
    let genres = this.state.CurrentValue.map(val => {
      return(<li>{val}</li>)
    })
    return(
      <section>
        <ul>
          {genres}
        </ul>
        <ChildContainer
          CallParent={this.PropMethod}
          />
      </section>
    )
  }
}



class App extends React.Component 
{
  constructor(props) 
  {
    super(props);
  }
  


  

  
  render() {
    return(
      <section>
        <ParentContainer/>
      </section>
    )
  }
}


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

<强>更新 它现在应该工作:D

还有另一种方式。请记住,所有这些组件都是类。您可以创建两者的实例,并将一个函数传递给其他道具。这样你就可以在不将它们嵌套在一起的情况下完成它。