2017-07-15 260 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`服務器端
相關問題