如何在 React Router v4 路由之间共享应用程序状态 [英] How to share application State between React Router v4 routes

查看:58
本文介绍了如何在 React Router v4 路由之间共享应用程序状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我不使用任何状态管理库.我只使用"React.

全局应用程序状态存储在组件 中.它包含一组 restaurant 对象.

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

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

我曾经通过作为道具传递给子组件的函数更新状态,但在这种情况下我不能更新状态,因为 MyFoodApp 不是 RestaurantPage 的父级.

我是否必须设置 Redux 来解决这个问题,或者是否有任何解决方法?

从'react'导入React;从 'react-dom' 导入 ReactDOM;import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';从'./js/components/EasyFoodApp'导入EasyFoodApp;从'./js/components/RestaurantPage'导入RestaurantPage;从 './js/components/NotFound' 导入 NotFound;类根扩展 React.Component {使成为() {返回 (<路由器><div className="路由器"><开关><路由精确路径="/" component={MyFoodApp}/><路线路径="/餐厅/:slug"组件={RestaurantPage}/><路由渲染={()=><NotFound/>}/></开关>

</路由器>);}}ReactDOM.render(, document.getElementById('root'));

我发现了旧的相关帖子,例如 这个这个但是有可能是处理这个问题的新方法.

解决方案

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

第一:提升状态,

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

class Root extends React.Component {状态 = {restaurant: []//在这里存储餐厅数据而不是 MyFoodApp}restaurantUpdater = () =>{//更新状态的实用函数}使成为() {返回 (<路由器><div className="路由器"><开关><路由精确路径="/" render={props =><MyFoodApp {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater}/>}/><路线路径="/餐厅/:slug"渲染={道具=><RestaurantPage {...props} restaurant={this.state.data} restaurantUpdater={this.restaurantUpdater}/>}/><路由渲染={(道具)=><NotFound {...props}/>}/></开关>

</路由器>);}}

第二:利用Context API

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

<块引用>

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

您可以使用 React 16.3 上下文 API喜欢

export const RestaurantContext = React.createContext({餐厅: [],restaurantUpdater: () =>{},});class RestaurantProvider 扩展了 React.Component {状态 = {restaurant: []//在这里存储餐厅数据而不是 MyFoodApp}restaurantUpdater = () =>{//更新状态的实用函数}使成为() {<RestaurantContext.Provider value={this.state}>{this.props.children}</RestaurantContext.Provider>}}

然后为消费者创建一个 HOC

从 'path/to/restaurantContext' 导入 RestaurantContextconst withContext = (Component) =>{返回(道具)=><RestaurantContext.Consumer>{(餐厅,餐厅更新程序)=><组件{...props} restaurant={restaurant} restaurantUpdater={restaurantUpdater}/>}</RestaurantContext.Consumer>}

现在你可以像这样在组件中使用它

导出默认 withContext(MyFoodApp);

并且您的 FoodApp 可以使用 restaurantrestaurantUpdater 来自像

这样的道具

const { restaurant, restaurantUpdater} = this.props

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

I would like to know what kind of solutions I have to solve the following issue:

I don't use any state mangement library. I "only use" React.

The global application state is stored in the component <MyFoodApp/>. It contains an array of restaurant objects.

The component RestaurantPage is used to display the details of a restaurant and allows to create a new review.

At this point I'm stuck because I need to update a specific restaurant object stored in the state of <MyFoodApp /> in order to add this submitted review.

I used to update the state via functions passed as props to the children components but in this case I can't because MyFoodApp is not a parent of RestaurantPage.

Do I have to set up Redux to fix this issue or is there any workarounds ?

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

I found old related posts like this one or this one but there is maybe a new way to handle this issue.

解决方案

There are a couple of solution to your problem without actually using a state management library,

First: Lift the state up,

This is the most correct solution since your components and routes are not highly nested and the data needs to handled by the components which are siblings of each other,

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

Second: Make use of Context API

You can make use of Context when your data needs to be passed down to components at different levels. As the react docs say

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.

You can configure the use of context using 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>
   }
}

and then create an HOC for the consumer

import RestaurantContext from 'path/to/restaurantContext'
const withContext = (Component) => {
    return (props) => <RestaurantContext.Consumer>
        {(restaurant, restaurantUpdater) => <Component {...props} restaurant={restaurant} restaurantUpdater={restaurantUpdater} />}
    </RestaurantContext.Consumer>
}

Now you can use it in the component like

export default withContext(MyFoodApp);

and your FoodApp can use restaurant and restaurantUpdater from props like

const { restaurant, restaurantUpdater} = this.props

similarly you can use it in the other components

这篇关于如何在 React Router v4 路由之间共享应用程序状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆