首页 文章

React js:我可以将数据从组件传递到另一个组件吗?

提问于
浏览
0

我是React的新手,我还在学习它 . 我正在做个人项目 .

让我解释一下我的问题:

我有一个名为 <NewReleases /> 的组件,我在那里进行ajax调用,并在今天的电影院中播放一些关于电影的数据 . (我拿 Headers ,海报img,概述等...)我把所有数据都放在 <NewReleases /> 状态,这样状态变成一个包含每个电影对象的对象,每个对象包含 Headers 字符,海报属性等......然后我渲染组件,使其看起来像电影海报,信息等制作的网格 . 这很好用 .

然后我需要一个组件 <Movie /><NewReleases /> 的状态获取一些数据并在HTML上呈现它们 . 我读了其他问题,其中人们有类似的问题,但它是不同的,因为他们有一个由父组件呈现的子组件 . 以这种方式,人们建议将州作为道具 . 我不能这样做,因为我的 <Movie /> 组件不是由 <NewReleases /> 呈现的 . <NewReleases /> 进行ajax调用,仅根据检索到的数据呈现JSX网格 .

index.js 我以这种方式设置主页面:

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Switch, Route} from 'react-router-dom';

import {Home} from './home';
import {Movie} from './movie';
import './css/index.css';

class App extends React.Component {
  render() {
    return(
      <BrowserRouter>
        <Switch>
          <Route path={'/movie/:movieTitle'} component={Movie} />
          <Route path={'/'} component={Home} />
        </Switch>
      </BrowserRouter>
    );
  }
}

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

(你在这里看不到 <NewReleases /> 因为它是在 <Home /> 组件内部渲染的,它也会渲染页眉和页脚 . )

因此,当我点击由 <NewReleases /> 呈现的电影时,该应用程序将让我继续 localhost:3000/movie/:movieTitle 其中:movieTitle是一种动态的方式来表达电影的 Headers (例如,如果我点击由 <NewReleases /> 呈现的星球大战的海报,我将继续 localhost:3000/movie/StarWars ) . 在该页面上,我想显示有关该电影的详细信息 . 信息存储在 <NewReleases /> 状态,但我无法从 <Movie /> (我猜)访问该状态 .

我希望你得到我想要达到的目标 . 我不知道是否有可能 . 我有一个想法:在 <Movie /> 我可以为我想要的电影做另一个ajax调用,但我认为它会更慢,而且我认为它不会是一个很好的解决方案与React .

请注意,我没有使用Redux,Flux等......只有React . 我希望在转向其他技术之前很好地理解React .

3 回答

  • 0

    你想做的方式更复杂 . 随着父母组件很容易做到 . 而Redux则更容易 .

    但是,你想要这样 . 我想如果你在应用程序中有一个状态,传递给家庭一个道具来设置一个电影状态并将这个电影状态传递给组件Move,工作正常 .

    问题是Route不会传递道具 . 所以你可以做一个可扩展的路线 . 在下面的代码中,我从网上获得了这个PropsRoute .

    import React from 'react';
    import ReactDOM from 'react-dom';
    import {BrowserRouter, Switch, Route} from 'react-router-dom';
    
    import {Home} from './home';
    import {Movie} from './movie';
    import './css/index.css';
    
        class App extends React.Component {
          constructor() {
            super();
    
            this.state = {
              movie: {}
            }
    
            this.setMovie = this.setMovie.bind(this);
          }
    
          setMovie(newMovie) {
            this.setState({
              movie: newMovie
            });
          }
    
          render() {
            return(
              <BrowserRouter>
                <Switch>
                  <PropsRoute path={'/movie/:movieTitle'} movie={this.state.movie} component={Movie} />
                  <PropsRoute path={'/'} component={Home} setMovie={this.setMovie} />
                </Switch>
              </BrowserRouter>
            );
          }
        }
    
        ReactDOM.render(
          <App />,
          document.getElementById('root')
        );
    
    
    -----
    const renderMergedProps = (component, ...rest) => {
      const finalProps = Object.assign({}, ...rest);
      return (
        React.createElement(component, finalProps)
      );
    }
    
    const PropsRoute = ({ component, ...rest }) => {
      return (
        <Route {...rest} render={routeProps => {
          return renderMergedProps(component, routeProps, rest);
        }}/>
      );
    }
    

    我认为这可以解决你的问题 .

  • 0

    这是一个简单的例子 . 将您的状态存储在父组件中,并将状态向下传递给组件 . 此示例使用React Router 4,但它显示了如何通过状态将setMovie函数和影片信息传递给您的一个子组件 . https://codepen.io/w7sang/pen/owVrxW?editors=1111

    当然,你必须重新设计这个以匹配你的应用程序,但基本的故障是你的主组件应该是你正在抓取你的电影信息的地方(通过AJAX或WS)然后设置功能将允许你将您需要的任何信息存储到父组件中,这最终将允许任何子组件访问您存储的信息 .

    const {
      BrowserRouter, 
      Link, 
      Route,
      Switch
    } = ReactRouterDOM;
    const Router = BrowserRouter;
    
    // App
    class App extends React.Component{
      constructor(props) {
        super(props);
        this.state = {
          movie: {
            title: null,
            rating: null
          }
        };
        this.setMovie = this.setMovie.bind(this);
      }
      setMovie(payload) {
        this.setState({
          movie: {
            title: payload.title,
            rating: payload.rating
          }
        });
      }
      render(){
        return(
        <Router>
          <div className="container">
            <Layout>
              <Switch>
                <Route path="/select-movie" component={ () => <Home set={this.setMovie} movie={this.state.movie} />}  /> 
                <Route path="/movie-info" component={()=><MovieInfo movie={this.state.movie}/>} /> 
              </Switch>
            </Layout>
          </div>
        </Router>
        )
      }
    }
    
    //Layout
    const Layout = ({children}) => (
      <div>
        <header>
          <h1>Movie App</h1>
        </header>
        <nav>
          <Link to="/select-movie">Select Movie</Link>
          <Link to="/movie-info">Movie Info</Link>
        </nav>
        <section>
          {children}
        </section>
      </div>
    )
    
    //Home Component
    const Home = ({set, movie}) => (
      <div>
        <Movie title="Star Wars VIII: The Last Jedi (2017)" rating={5} set={set} selected={movie} />
        <Movie title="Star Wars VII: The Force Awakens (2015)" rating={5} set={set} selected={movie} />
      </div>
    )
    
    //Movie Component for displaying movies
    //User can select the movie
    const Movie = ({title, rating, set, selected}) => {
      const selectMovie = () => {
        set({
          title: title,
          rating: rating
        });
      }
      return (
        <div className={selected.title === title ? 'active' : ''}>
          <h1>{title}</h1>
          <div>
            {Array(rating).fill(1).map(() =>
            <span>★</span>
            )}
          </div>
          <button onClick={selectMovie}>Select</button>
        </div>
      )
    }
    
    //Movie Info
    //You must select a movie before movie information is shown
    const MovieInfo = ({movie}) => {
      
      const {
        title,
        rating
      } = movie;
      
      //No Movie is selected
      if ( movie.title === null ) {
        return <div>Please Select a Movie</div>
      }
      
      //Movie has been selected
      return (
        <div>
          <h1>Selected Movie</h1>
          {title}
          {Array(rating).fill(1).map(() =>
            <span>★</span>
          )}
        </div>
      )
      
    }
    
    ReactDOM.render(<App />,document.getElementById('app'));
    
    nav {
      margin: 20px 0;
    }
    
    a {
      border: 1px solid black;
      margin-right: 10px;
      padding: 10px;
    }
    
    .active {
      background: rgba(0,0,0,0.2);
    }
    
    <div id="app"></div>
    
  • 0

    创建手册 object 存储到 get/set 电影信息并使用它 . 而已 . 请尝试以下代码 . 那应该回答你所有的问题 . 点击任何新版本,它将重定向到电影信息屏幕,其中包含所有详细信息 . 如果您对总是刷新的新版本数据感觉不好,您可能必须创建另一个商店,然后通过检查存储中存在的数据来确定数据 .

    Note: 使用存储并在浏览器URL中使用 title (可能出现重复项)会在用户刷新浏览器时出现问题 . 为此,在浏览器URL中使用 id ,使用AJAX调用获取详细信息并在存储中设置该详细信息 .

    //store for movie info
    const movieInfoStore = {
      data: null,
      set: function(data) {
        this.data = data;
      },
      clear: function() {
        this.data = null;
      }
    };
    
    class MovieInfo extends React.Component {
      componentWillUnmount() {
        movieInfoStore.clear();
      }
      
      render() {
        return (
          <div>
            <pre>
              {movieInfoStore.data && JSON.stringify(movieInfoStore.data)}
            </pre>
            <button onClick={() => this.props.history.goBack()}>Go Back</button>
          </div>
        )
      }
    }
    
    MovieInfo = ReactRouterDOM.withRouter(MovieInfo);
    
    class NewReleases extends React.Component {
      handleNewReleaseClick(newRelease) {
        movieInfoStore.set(newRelease);
        this.props.history.push(`/movie/${newRelease.title}`);
      }
      
      render() {
        const { data, loading } = this.props;
        
        if(loading) return <b>Loading...</b>;
        
        if(!data || data.length === 0) return null;
        
        return (
          <ul>
            {
              data.map(newRelease => {
                return (
                  <li onClick={() => this.handleNewReleaseClick(newRelease)}>{newRelease.title}</li>
                )
              })
            }
          </ul>
        )
      }
    }
    
    NewReleases = ReactRouterDOM.withRouter(NewReleases);
    
    class Home extends React.Component {
      constructor(props) {
        super(props);
        
        this.state = {
          newReleases: [],
          newReleasesLoading: true
        };
      }
    
      componentDidMount() {
        setTimeout(() => {
          this.setState({
            newReleases: [{id: 1, title: "Star Wars"}, {id: 2, title: "Avatar"}],
            newReleasesLoading: false
          });
        }, 1000);
      }
    
      render() {
        const { newReleases, newReleasesLoading } = this.state;
      
        return (
          <NewReleases data={newReleases} loading={newReleasesLoading} />
        )
      }
    }
    
    class App extends React.Component {
      render() {
        const { BrowserRouter, HashRouter, Switch, Route } = ReactRouterDOM;
      
        return (
          <HashRouter>
            <Switch>
              <Route path="/movie/:movieTitle" component={MovieInfo} />
              <Route path="/" component={Home} />
            </Switch>
          </HashRouter>
        )
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
    
    <div id="root"></div>
    

相关问题