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

IT技术 javascript reactjs react-router-v4
2021-05-14 21:48:03

我想知道我必须使用什么样的解决方案来解决以下问题:

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

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

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

在这一点上,我被卡住了,因为我需要更新 restaurant存储在状态中的特定对象<MyFoodApp />才能添加此提交的评论

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

我找到了像这个这个这样的旧相关帖子,但可能有一种新的方法来处理这个问题。

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文档所说

不要仅仅为了避免将props向下传递几级而使用上下文。坚持需要在多个级别的多个组件中访问相同数据的情况。

您可以使用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

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

如果任一场景与您的组件排列相匹配,您就可以在没有 redux 的情况下管理数据:

  1. 父子关系:使用props
  2. 子父关系:使用回调
  3. 有共同父母的兄弟姐妹

但是这两种关系都不能满足您对组件的安排,因为这两个组件是新的根组件。

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

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

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

我希望它会有所帮助