如何在 React Router v4 路由之间共享应用程序状态
How to share application State between React Router v4 routes
我想知道我有什么样的解决方案来解决以下问题:
我不使用任何状态管理库。我 "only use" 反应。
全局应用程序状态存储在组件<MyFoodApp/>
中。它包含一组 餐厅 个对象。
组件 RestaurantPage
用于显示餐厅的详细信息,并允许 创建新评论。
此时我卡住了,因为我需要 更新存储在 <MyFoodApp />
状态下的特定 restaurant
对象,以便添加 这次提交的评论.
我过去常常通过作为道具传递给子组件的函数来更新状态,但在这种情况下我不能,因为 MyFoodApp
不是 RestaurantPage
的父级。
我是否必须设置 Redux
才能解决此问题,或者是否有任何解决方法?
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import EasyFoodApp from './js/components/EasyFoodApp';
import RestaurantPage from './js/components/RestaurantPage';
import NotFound from './js/components/NotFound';
class Root extends React.Component {
render() {
return (
<Router>
<div className="router">
<Switch>
<Route exact path="/" component={MyFoodApp} />
<Route
path="/restaurant/:slug"
component={RestaurantPage}
/>
<Route render={() => <NotFound />} />
</Switch>
</div>
</Router>
);
}
}
ReactDOM.render(<Root />, document.getElementById('root'));
我找到了像 or 这样的旧相关帖子,但也许有一种新方法可以解决这个问题。
您的问题有几个解决方案,无需实际使用状态管理库,
第一:状态提升,
这是最正确的解决方案,因为您的组件和路由没有高度嵌套,并且数据需要由彼此为兄弟的组件处理,
class Root extends React.Component {
state = {
restaurant: [] // store the restaurant data here instead of MyFoodApp
}
restaurantUpdater = () => {
//utility function to update state
}
render() {
return (
<Router>
<div className="router">
<Switch>
<Route exact path="/" render={props => <MyFoodApp {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater} />} />
<Route
path="/restaurant/:slug"
render={props => <RestaurantPage {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater} />}
/>
<Route render={(props) => <NotFound {...props}/>} />
</Switch>
</div>
</Router>
);
}
}
其二:利用上下文API
当您的数据需要向下传递到不同级别的组件时,您可以使用 Context
。正如反应文档所说
Don’t use context just to avoid passing props a few levels down. Stick
to cases where the same data needs to be accessed in many components
at multiple levels.
您可以使用React 16.3 context API
like
配置上下文的使用
export const RestaurantContext = React.createContext({
restaurant: [],
restaurantUpdater: () => {},
});
class RestaurantProvider extends React.Component {
state = {
restaurant: [] // store the restaurant data here instead of MyFoodApp
}
restaurantUpdater = () => {
//utility function to update state
}
render() {
<RestaurantContext.Provider value={this.state}>
{this.props.children}
</RestaurantContext.Provider>
}
}
然后为消费者创建一个 HOC
import RestaurantContext from 'path/to/restaurantContext'
const withContext = (Component) => {
return (props) => <RestaurantContext.Consumer>
{(restaurant, restaurantUpdater) => <Component {...props} restaurant={restaurant} restaurantUpdater={restaurantUpdater} />}
</RestaurantContext.Consumer>
}
现在你可以像这样在组件中使用它了
export default withContext(MyFoodApp);
并且您的 FoodApp 可以使用 restaurant
和 restaurantUpdater
来自像
这样的道具
const { restaurant, restaurantUpdater} = this.props
同样你可以在其他组件中使用它
您的答案的解决方案是创建子路由,以创建从 MyFoodApp 组件到 RestaurantPage 组件的子路由。
在 MyFoodApp 的渲染方法中 *注意:不要在路由中再次使用开关
<Switch>
<Route exact path="/restaurant" render={() => <RestaurantPage pages={this.arrayOfRestaurant}/>
</Switch>
希望对您有所帮助
如果任一场景符合您的组件安排,您可以在没有 redux 的情况下管理数据:
- Parent 到 child 关系:使用 Props
- Child 到 parent 关系:使用回调
- 兄弟姐妹有共同点parent。
但是这两个关系都不满足你对组件的排列,因为这两个组件是新的根组件。
当组件无法在任何类型的 parent-child 关系之间进行通信时,documentation 建议设置一个全局事件系统。
我想知道我有什么样的解决方案来解决以下问题:
我不使用任何状态管理库。我 "only use" 反应。
全局应用程序状态存储在组件<MyFoodApp/>
中。它包含一组 餐厅 个对象。
组件 RestaurantPage
用于显示餐厅的详细信息,并允许 创建新评论。
此时我卡住了,因为我需要 更新存储在 <MyFoodApp />
状态下的特定 restaurant
对象,以便添加 这次提交的评论.
我过去常常通过作为道具传递给子组件的函数来更新状态,但在这种情况下我不能,因为 MyFoodApp
不是 RestaurantPage
的父级。
我是否必须设置 Redux
才能解决此问题,或者是否有任何解决方法?
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import EasyFoodApp from './js/components/EasyFoodApp';
import RestaurantPage from './js/components/RestaurantPage';
import NotFound from './js/components/NotFound';
class Root extends React.Component {
render() {
return (
<Router>
<div className="router">
<Switch>
<Route exact path="/" component={MyFoodApp} />
<Route
path="/restaurant/:slug"
component={RestaurantPage}
/>
<Route render={() => <NotFound />} />
</Switch>
</div>
</Router>
);
}
}
ReactDOM.render(<Root />, document.getElementById('root'));
我找到了像
您的问题有几个解决方案,无需实际使用状态管理库,
第一:状态提升,
这是最正确的解决方案,因为您的组件和路由没有高度嵌套,并且数据需要由彼此为兄弟的组件处理,
class Root extends React.Component {
state = {
restaurant: [] // store the restaurant data here instead of MyFoodApp
}
restaurantUpdater = () => {
//utility function to update state
}
render() {
return (
<Router>
<div className="router">
<Switch>
<Route exact path="/" render={props => <MyFoodApp {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater} />} />
<Route
path="/restaurant/:slug"
render={props => <RestaurantPage {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater} />}
/>
<Route render={(props) => <NotFound {...props}/>} />
</Switch>
</div>
</Router>
);
}
}
其二:利用上下文API
当您的数据需要向下传递到不同级别的组件时,您可以使用 Context
。正如反应文档所说
Don’t use context just to avoid passing props a few levels down. Stick to cases where the same data needs to be accessed in many components at multiple levels.
您可以使用React 16.3 context API
like
export const RestaurantContext = React.createContext({
restaurant: [],
restaurantUpdater: () => {},
});
class RestaurantProvider extends React.Component {
state = {
restaurant: [] // store the restaurant data here instead of MyFoodApp
}
restaurantUpdater = () => {
//utility function to update state
}
render() {
<RestaurantContext.Provider value={this.state}>
{this.props.children}
</RestaurantContext.Provider>
}
}
然后为消费者创建一个 HOC
import RestaurantContext from 'path/to/restaurantContext'
const withContext = (Component) => {
return (props) => <RestaurantContext.Consumer>
{(restaurant, restaurantUpdater) => <Component {...props} restaurant={restaurant} restaurantUpdater={restaurantUpdater} />}
</RestaurantContext.Consumer>
}
现在你可以像这样在组件中使用它了
export default withContext(MyFoodApp);
并且您的 FoodApp 可以使用 restaurant
和 restaurantUpdater
来自像
const { restaurant, restaurantUpdater} = this.props
同样你可以在其他组件中使用它
您的答案的解决方案是创建子路由,以创建从 MyFoodApp 组件到 RestaurantPage 组件的子路由。
在 MyFoodApp 的渲染方法中 *注意:不要在路由中再次使用开关
<Switch>
<Route exact path="/restaurant" render={() => <RestaurantPage pages={this.arrayOfRestaurant}/>
</Switch>
希望对您有所帮助
如果任一场景符合您的组件安排,您可以在没有 redux 的情况下管理数据:
- Parent 到 child 关系:使用 Props
- Child 到 parent 关系:使用回调
- 兄弟姐妹有共同点parent。
但是这两个关系都不满足你对组件的排列,因为这两个组件是新的根组件。
当组件无法在任何类型的 parent-child 关系之间进行通信时,documentation 建议设置一个全局事件系统。