将状态传递给React中的多个子组件

时间:2017-06-24 12:21:47

标签: reactjs react-router

我无法理解如何将状态作为道具传递给React中的其他子组件。在我的代码中,你可以看到我有一个接受输入的组件并将其映射到我的状态数组,在另一个组件中显示部分数据,这样就可以了。

但总体目标是,当用户点击他们已添加到列表中的项目时,React Router会启动并将视图更改为MovieDetails组件,这将包含他们输入的额外信息,如标题,日期和说明。

我甚至没有设置反应路由器,因为我似乎无法正确访问MovieDetails组件中的状态。然后我不太确定如何用路由器显示正确的MovieDetails组件。

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import './App.css';

class App extends Component {
  constructor() {
    super();
    this.addMovie = this.addMovie.bind(this);
    this.state = {
      movies : []
    };
  }

  addMovie(movie) {
    let movies = this.state.movies;
    movies.push(movie);
    this.setState({ movies });
  }

  render() {
    return (
      <div className="wrapper">
        <div className="container">
          <div>
            <h3 className="heading">Favorite Movies</h3>
          </div>
        </div>
        <div>
          <AddMovie addMovie={ this.addMovie }/>
          <MovieList movies={ this.state.movies }/>
        </div>
      </div>
    )
  }
}

class AddMovie extends Component {
  addMovie(event) {
    event.preventDefault();
    const movie = {
      title : this.title.value,
      year  : this.year.value,
      image : this.image.value,
      desc  : this.desc.value
    }
    this.props.addMovie(movie);
    this.movieForm.reset();
  }
  render() {
    return (
      <div className="container">
        <form ref={(input) => this.movieForm = input} onSubmit={(e) => this.addMovie(e)}>
          <input ref={(input) => this.title = input} className="Input" type="text" placeholder="Title"/>
          <input ref={(input) => this.year = input} className="Input" type="text" placeholder="Year"/>
          <textarea ref={(input) => this.desc = input} className="Input" type="text" placeholder="Description"></textarea>
          <input ref={(input) => this.image = input} className="Input" type="text" placeholder="Poster URL"/>
          <button type="submit">Add</button>
        </form>
      </div>
    )
  }
}

class MovieList extends Component {
  render() {
    return (
      <div>
        { this.props.movies.map( (movie, i) => <MovieListItem key={i} details={ movie }/> )}
      </div>
    );
  }
}

class MovieListItem extends Component {
  constructor(props) {
    super(props);
    this.toggleClass = this.toggleClass.bind(this);
    this.state = {
      active: false
    };
  }
  toggleClass() {
    const currentState = this.state.active;
    this.setState({ active: !currentState });
  }
  render() {
    const { details } = this.props;
    return (
      <div
        className={this.state.active ? "red": null}
        onClick={this.toggleClass}
      >
        <img src={details.image} alt=""/>
        <hr/>
      </div>
    )
  }
}

class MovieDetails extends Component {
  render() {
    return (
      <div>
        <p>title here</p>
        <p>year here</p>
        <p>description here</p>
        <img src="image" alt=""/>
      </div>
    )
  }
}

export default App;

2 个答案:

答案 0 :(得分:0)

如果我做对了,当你点击从MovieList创建的项目时,你是否想要推送到一个新的组件(details应该可以访问)?如果是这样,您需要执行以下步骤:

  1. 如果您想推送新视图,则必须使用“react-router”中的browserHistoryhashHistory。在这种情况下,我将使用browserHistory
  2. 要访问MovieDetails组件中的状态,只需将其传递给browserHistory
  3. 以下是我在单击MovieList组件中的项目时使用代码推送到新视图的方式:

    import {Router, Route, browserHistory} from "react-router";
    
    class Routes extends Component {
      render() {
        let props = this.props;
    
        return (
          <Router history={browserHistory}>
            <Route path="/" component={App}/>
            <Route path="/movie-details" component={MovieDetails}/>
          </Router>
        )
      }
    }
    
    // Here is your App component
    class App extends Component {
      // ... your code
    }
    
    // ... your other classes
    
    
    class MovieListItem extends Component {
      // ... Constructor 
      // Here I'm pushing the new route for MovieDetails view
      toggleClass(details) {
        browserHistory.push({
          pathname: '/movie-details',
          state: details // pass the state to MovieDetails
        });
        // ... your code
      }
    
      render() {
        const {details} = this.props;
    
        return (
          <div
           // ... your code
           onClick={this.toggleClass.bind(this, details)} // pass details to toggleClass() 
          >
          // ... your code
          </div>
        )
      }
    }    
    
    // Here is your Movie Details component
    class MovieDetails extends Component { 
      console.log('This props: ', this.props.location.state); // The details object should be logged here
      // ... your code
    }
    
    // Export Routes instead of App
    export default Routes;
    

    希望有所帮助!

答案 1 :(得分:0)

问题来自您尝试访问输入值的方式。当您使用ref时,您会得到一个React包装器,而不是真正的DOM元素,因此您无法直接访问.value.reset()。您必须使用getDOMNode()方法来获取DOM元素。这对我有用:

const movie = {
  title : this.title.getDOMNode().value,
  year  : this.year.getDOMNode().value,
  image : this.image.getDOMNode().value,
  desc  : this.desc.getDOMNode().value
};

...

this.movieForm.getDOMNode().reset();

另一方面,当你setState使用当前状态的东西时,你应该使用回调:

addMovie(newMovie) {
  this.setState(({movies: prevMovies})=> ({
    movies: [...prevMovies, newMovie]
  }));
}

查看来自official doc

的完整setState API