我是React的新手,我还在学习它。我正在做个人项目。
让我解释一下我的问题:
我有一个名为<NewReleases />
的组件,我在那里进行ajax调用,并在今天的电影院中播放一些关于电影的数据。 (我拿标题,海报img,概述等...)我把所有数据都放在<NewReleases />
状态,这样状态变成一个包含每个电影对象的对象,每个对象包含标题字符,海报属性等。 ..然后我渲染组件,使其看起来像电影海报,信息等制作的网格。这很有效。
然后我需要一个组件<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是一种动态的方式来表达电影的标题(例如,如果我点击<NewReleases />
呈现的星球大战海报,我将继续localhost:3000/movie/StarWars
)。在该页面上,我想显示有关该电影的详细信息。信息存储在<NewReleases />
状态,但我无法从<Movie />
访问该状态(我猜)。
我希望你得到我想要达到的目标。我不知道是否有可能。我有一个想法:在<Movie />
我可以为我想要的电影做另一个ajax电话,但我觉得它会慢一些,而且我也不认为这对React来说是一个很好的解决方案。
请注意,我没有使用Redux,Flux等......只有React。我想在转向其他技术之前很好地理解React。
答案 0 :(得分:0)
你想做的事情更复杂。随着父母组件很容易做到。使用Redux更容易。
但是,你想要这样。我想如果你在应用程序中有一个状态,将一个道具设置为电影状态并将此电影状态传递给组件Move,工作正常。
问题是Route不会传递道具。所以你可以做一个可扩展的路线。在下面的代码中,我从网上获得了这个PropsRoute。
start_requests()
我认为这可以解决您的问题。
答案 1 :(得分: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>
答案 2 :(得分:0)
创建手动object
商店以get/set
电影信息并使用它。而已。请尝试以下代码。那应该回答你所有的问题。点击任何新版本,它将重定向到电影信息屏幕,其中包含所有详细信息。如果您对总是刷新的新版本数据感到不满,则可能需要创建另一个商店,然后通过检查商店中存在的数据来get/set
数据。
注意:使用商店并在浏览器网址中使用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>