如何在React Router v4路由之间共享应用程序状态

时间:2018-04-20 09:36:04

标签: javascript reactjs react-router-v4

我想知道我有什么样的解决方案来解决以下问题:

我不使用任何州管理库。我“只使用”React。

全局应用程序状态存储在组件<MyFoodApp/>中。它包含一系列 restaurant 对象。

组件RestaurantPage用于显示餐馆的详细信息,并允许创建新评论

此时我被卡住了,因为我需要更新以restaurant状态存储的特定 <MyFoodApp />对象,以便添加此提交的评论

我曾经通过作为道具传递到子组件的函数更新状态,但在这种情况下我不能,因为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'));

我找到了与this onethis one相关的旧相关帖子,但可能有一种新方法可以解决此问题。

3 个答案:

答案 0 :(得分:3)

在没有实际使用状态管理库的情况下,您可以解决几个问题,

首先:提升状态,

这是最正确的解决方案,因为您的组件和路由没有高度嵌套,并且数据需要由彼此兄弟的组件处理,

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>
        );
    }
}

第二:使用Context API

当您的数据需要传递到不同级别的组件时,您可以使用Context。正如反应文档所说

  

不要仅使用上下文来避免将道具向下移动几级。棒   在许多组件中需要访问相同数据的情况   在多个层面。

您可以使用React 16.3 context API

配置上下文的使用
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

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

答案 1 :(得分:0)

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

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

我希望它会有所帮助

答案 2 :(得分:0)

如果其中一个方案符合您的组件排列,则可以在没有redux的情况下管理数据:

  1. 父母与孩子的关系:使用道具
  2. Child to parent 关系:使用回调
  3. 兄弟姐妹与共同的父母。
  4. 但是这两种关系都不能满足您对组件的安排,因为这两个组件是新的根组件。

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