【问题标题】:Passing state to more than one child component in React在 React 中将状态传递给多个子组件
【发布时间】:2023-03-21 22:11:01
【问题描述】:

我无法理解如何将状态作为道具传递给 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;

【问题讨论】:

  • 我不太明白你的问题出在哪里。你能试着做一个片段,或者一个codePen吗?
  • 花了我一分钟,它不太正常,但它在 CodePen 上:codepen.io/anon/pen/jwLoaq?editors=0010 抱歉!

标签: reactjs react-router


【解决方案1】:

问题来自您尝试访问输入值的方式。当你使用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

【讨论】:

  • 谢谢!好的,如果我使用数组索引,我似乎能够访问 MovieDetails 组件内的数组中的数据。现在我想弄清楚如何使用路由器来显示 MovieDetails 组件以及用户单击的电影列表项中的相应数据。
  • 看官方文档,很清楚。只需使用正确的路由插入您的组件,例如 &lt;Router history={browserHistory}&gt; &lt;Route path="/add" component={AddMovie}/&gt; &lt;Route path="/list" component={MovieList}/&gt; &lt;/Router&gt;
【解决方案2】:

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

  1. 如果你想推送一个新视图,你必须使用'react-router'中的browserHistoryhashHistory。在这种情况下,我将使用browserHistory
  2. 要访问MovieDetails 组件中的状态,只需将其传递给browserHistory

当单击 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;

希望对您有所帮助!

【讨论】:

  • 嗯...我知道你要去哪里了,但我试过了,现在它只加载了 MovieDetails 组件,我的测试内容显示在页面上。而且我不能强迫它进入主页——它一直在加载 MovieDetails 的路径。尝试访问 MovieDetails 中的 MovieListItem 数据时仍然出现错误。
  • 再一次,你确定我的流程正确吗?这是一个.gif,您可以在其中查看MovieDetails 组件中收到的流程和道具。我编辑了我的代码,因此 toggleClass 与点击事件绑定。另外,我将孔路径记录到应该接收到MovieDetails 组件的状态。
  • 哦!哇。有用。好的,我使用 match.params 让它工作并获取 id,将其分配给一个变量并将其作为我的状态的数组索引传递。
  • 很高兴听到这个消息。如果您想对每个组件的状态进行良好的管理,我对您的建议是使用 redux,您可以在其中保留每条数据,以维护代码的受控版本。
猜你喜欢
  • 2019-01-20
  • 2022-01-18
  • 2019-08-09
  • 2020-07-04
  • 2022-07-15
  • 1970-01-01
  • 1970-01-01
  • 2019-03-08
  • 2017-04-30
相关资源
最近更新 更多