如何在 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 可以使用 restaurantrestaurantUpdater 来自像

这样的道具
const { restaurant, restaurantUpdater} = this.props

同样你可以在其他组件中使用它

您的答案的解决方案是创建子路由,以创建从 MyFoodApp 组件到 RestaurantPage 组件的子路由。

MyFoodApp 的渲染方法中 *注意:不要在路由中再次使用开关 <Switch> <Route exact path="/restaurant" render={() => <RestaurantPage pages={this.arrayOfRestaurant}/> </Switch>

希望对您有所帮助

如果任一场景符合您的组件安排,您可以在没有 redux 的情况下管理数据:

  1. Parent 到 child 关系:使用 Props
  2. Child 到 parent 关系:使用回调
  3. 兄弟姐妹有共同点parent。

但是这两个关系都不满足你对组件的排列,因为这两个组件是新的根组件。

当组件无法在任何类型的 parent-child 关系之间进行通信时,documentation 建议设置一个全局事件系统。