2017-07-15 258 views
0

我是React的新手,我仍然在学习它。我正在做一个个人项目。React js:我可以将数据从一个组件传递到另一个组件吗?

让我解释一下我的问题:

我有一个名为<NewReleases />,我让Ajax调用,今天采取一些DATAS的一些电影出来电影院组件。 (我拿标题,海报img,概述等等......)我把所有的数据都放在<NewReleases />状态,这样状态变成了一个包含每个电影对象的对象,并且每个对象都包含标题属性,海报属性等......然后我渲染组件,使其看起来像由电影海报,信息等制作的网格。这效果很好。

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

index.js我已经设置了主网页是这样的:(你看不到<NewReleases />这里,因为它是<Home />组件,该组件还呈现页眉和页脚的内部渲染)

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 />呈现的电影时,该应用将让我继续localhost:3000/movie/:movieTitle其中:movieTitle是一种动态的说电影标题的方式(例如,如果我点击星球大战渲染的海报<NewReleases />,我会继续localhost:3000/movie/StarWars)。在那个页面上,我想展示关于那部电影的详细信息。信息存储在<NewReleases />状态,但我不能从<Movie />(我想)访问该状态。

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

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

+0

。 (保持简单) – taha

+0

不,你不能。你将不得不使用一些肮脏的黑客。这就是为什么我讨厌反应。 –

回答

0

你想要做的方式更复杂。随着父母的组成部分,这很容易做到。 Redux更容易。

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

问题是路由不通过道具。所以你可以做一个可扩展的路线。在下面的代码中,我从Web这个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)抓住你的电影信息,然后set函数将允许您将所需的任何信息存储到父组件中,这将最终允许任何子组件访问您存储的信息。

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

创建手工objectget/set电影信息,并使用它。而已。尝试下面的代码。这应该回答你所有的问题。点击任何新版本,它将重定向到电影信息屏幕的所有细节。如果您对新版本数据感觉不好时总会提醒您,您可能需要创建另一个商店,然后通过检查数据存储在get/set数据中。

注意:在浏览器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>

如果你希望你的数据是全球可用使用`localStorage`在客户端或`Database`服务器端
相关问题