没有 redux 的 React 导航状态管理
React navigation state management without redux
我正在为我的 React Native 项目使用 React Navigation 库,并且努力了解如何使用它处理状态。
在普通的 React Native 应用程序中,我可以在顶级组件中拥有状态,并通过道具从子组件弹出事件,但是对于 React Navigation,我似乎无法将任何道具传递给用作屏幕的组件。
通读 related GitHub issue 后,我认为库开发人员似乎非常固执己见,强迫每个人使用某种全局事件处理程序 - 我猜是 redux 或 mobx。
The handler which needs to modify the following state。当我开始尝试在应用程序内移动状态时,我卡住了,因为我不知道如何:
- 将处理程序传递给 TaskForm 组件。
- 如果它作为 App.js
的一部分呈现,则将状态作为道具传递给 TaskList
请避免回复 "just use redux"。我相信在这个例子中使用 redux 会大材小用。
我在没有 redux 的情况下在我的应用程序中使用 react native 和 react navigation,到目前为止它运行良好。诀窍是一直传递 screenProps
。
例如,我有更多视图。我在堆栈中创建了一个包含 2 个子视图的基本更多视图:
class More extends Component {
render() {
return <something>
}
}
class SubView1 extends Component {...}
class SubView2 extends Component {...}
然后我创建堆栈:
const MoreStack = StackNavigator({
More: {
screen: More
},
SubView1: {
screen: SubView1,
},
...
}, options);
然后我创建一个包装器 class 我导出:
export default class MoreExport extends Component {
static navigationOptions = {
title: "More"
}
render() {
return <MoreStack screenProps={this.props.screenProps} />;
}
}
如果所有这些都在 More.js 中,我可以从 More.js 中导入更多并在其他任何地方使用它。
如果我然后将 screenProps 传递到我的根视图,然后为每个层都有一个包装器 class,我可以一直向下传递 screenProps,并且所有视图都可以使用 this.props.screenProps
.
我在每个 StackNavigator 和 TabNavigator 周围都使用了类似上面的包装器,并且 screenProps 一直向下传递。
例如,在我的根 class 的渲染方法中,我可以这样做:
return <More screenProps={{prop1: something, prop2: somethingElse}} />
然后 More class 和 MoreStack 中的每个 SubView 都可以访问这些道具。
如果您需要更多说明,请随时告诉我!
免责声明:我不知道这是正确的还是推荐的方法,但它确实有效
在受到 steffeydev 的启发后,我更多地关注了 React 社区问题,发现了一个非常简单的包装器使用函数的示例。
很意外simple solution也不知道为什么之前没想到。
函数如下:
const createComponent = (instance, props) =>
navProps => React.createElement(instance, Object.assign({}, props, navProps));
感谢您的启发,并向我指出 screenProps,这使我找到了这个解决方案。
您可以像这样设置导航参数:
static navigationOptions = ({ navigation }) => {
return {
tabBarIcon: ({ tintColor, focused }) =>
<View>
<Icon name="bell-ring" size={24} color={focused ? 'green' : 'black'} />
{(navigation.state.params.badgeCount && navigation.state.params.badgeCount > 0) ?
<Text>{navigation.state.params.badgeCount}</Text>
:
<View></View>
}
</View>
}
}
并将 badgeCount 更改为:
this.props.navigation.setParams({ badgeCount: 3 })
在发现 React Navigation 文档的以下部分之前,我一直在努力解决同样的问题并尝试了其他一些答案:https://reactnavigation.org/docs/en/stack-navigator.html#params.
本质上,Stack
中的每个 Screen
都可以传递 params
,其中可以包含处理程序,然后各种屏幕可以与应用程序状态进行交互。
然后我的一般结构是有一个带有状态和处理程序的 App
class,然后根据需要将处理程序传递到每个导航 Screen
。我不确定这个模式是否正确,但这是我理解一般 React 教程的方式。
示例:在我的演示应用程序中,我的页面流如下:
- 公园查找器屏幕 -> 公园详细信息屏幕(带有
Bookmark
操作)
- 书签列表屏幕 -> 公园详情屏幕
如果找到公园,可以单击 Bookmark
按钮,将公园添加到书签屏幕上显示的书签列表中。然后您可以单击公园书签查看详细信息。
我的 App
大致是这样的:
import React, { Component } from 'react';
// Screens
import ParkFinderScreen from './Components/ParkFinderScreen';
import ParkBookmarksScreen from './Components/ParkBookmarksScreen';
import ParkDetailsScreen from './Components/ParkDetailsScreen';
// Navigation
import { createStackNavigator, createBottomTabNavigator, createAppContainer } from 'react-navigation';
class App extends Component {
constructor(props) {
super(props);
this.state = {
bookmarks: new Map()
};
}
// Bookmark the park shown in the detail section.
handleBookmark (park) {
let newBookmarks = this.state.bookmarks;
newBookmarks.set(park.parkCode, park);
this.setState({
bookmarks: newBookmarks
});
}
render() {
const FinderStack = createStackNavigator(
{
ParkFinder: {
screen: ParkFinderScreen
},
ParkFinderDetails: {
screen: ParkDetailsScreen,
params: {
handleBookmark: (park) => this.handleBookmark(park),
}
},
}
);
const BookmarksStack = createStackNavigator(
{
ParkBookmarks: {
screen: ParkBookmarksScreen,
params: {
bookmarks: this.state.bookmarks
}
},
ParkBookmarksDetails: {
screen: ParkDetailsScreen,
},
}
);
const AppNavigator = createBottomTabNavigator(
{
Bookmarks: BookmarksStack,
Finder: FinderStack,
}
);
const AppContainer = createAppContainer(AppNavigator);
return (
<AppContainer/>
);
}
}
export default App;
我正在使用 Apollo Client,但我删除了那些部分。
在 Screen
组件中,您可以使用 this.props.navigation.getParam('bookmarks')
.
像访问其他组件一样访问 props
我遇到的一个问题是,每当我更改应用程序状态时,我都会被带到第一个屏幕。状态已更新,但有点迷失方向。我不确定是否有办法在停留在屏幕上的同时更新 App 状态。我可以理解,鉴于 App 状态已更新,所有子项都需要更新,因此当前屏幕(我认为是子项的一部分)将被重置。我不知道这是系统的限制还是我设计组件的副产品。
我希望这对某人有所帮助。这似乎符合 React Native 的预期行为。库团队似乎真的希望你不要使用 Redux。 https://reactnavigation.org/docs/en/redux-integration.html
我正在为我的 React Native 项目使用 React Navigation 库,并且努力了解如何使用它处理状态。 在普通的 React Native 应用程序中,我可以在顶级组件中拥有状态,并通过道具从子组件弹出事件,但是对于 React Navigation,我似乎无法将任何道具传递给用作屏幕的组件。
通读 related GitHub issue 后,我认为库开发人员似乎非常固执己见,强迫每个人使用某种全局事件处理程序 - 我猜是 redux 或 mobx。
The handler which needs to modify the following state。当我开始尝试在应用程序内移动状态时,我卡住了,因为我不知道如何:
- 将处理程序传递给 TaskForm 组件。
- 如果它作为 App.js 的一部分呈现,则将状态作为道具传递给 TaskList
请避免回复 "just use redux"。我相信在这个例子中使用 redux 会大材小用。
我在没有 redux 的情况下在我的应用程序中使用 react native 和 react navigation,到目前为止它运行良好。诀窍是一直传递 screenProps
。
例如,我有更多视图。我在堆栈中创建了一个包含 2 个子视图的基本更多视图:
class More extends Component {
render() {
return <something>
}
}
class SubView1 extends Component {...}
class SubView2 extends Component {...}
然后我创建堆栈:
const MoreStack = StackNavigator({
More: {
screen: More
},
SubView1: {
screen: SubView1,
},
...
}, options);
然后我创建一个包装器 class 我导出:
export default class MoreExport extends Component {
static navigationOptions = {
title: "More"
}
render() {
return <MoreStack screenProps={this.props.screenProps} />;
}
}
如果所有这些都在 More.js 中,我可以从 More.js 中导入更多并在其他任何地方使用它。
如果我然后将 screenProps 传递到我的根视图,然后为每个层都有一个包装器 class,我可以一直向下传递 screenProps,并且所有视图都可以使用 this.props.screenProps
.
我在每个 StackNavigator 和 TabNavigator 周围都使用了类似上面的包装器,并且 screenProps 一直向下传递。
例如,在我的根 class 的渲染方法中,我可以这样做:
return <More screenProps={{prop1: something, prop2: somethingElse}} />
然后 More class 和 MoreStack 中的每个 SubView 都可以访问这些道具。
如果您需要更多说明,请随时告诉我!
免责声明:我不知道这是正确的还是推荐的方法,但它确实有效
在受到 steffeydev 的启发后,我更多地关注了 React 社区问题,发现了一个非常简单的包装器使用函数的示例。
很意外simple solution也不知道为什么之前没想到。
函数如下:
const createComponent = (instance, props) =>
navProps => React.createElement(instance, Object.assign({}, props, navProps));
感谢您的启发,并向我指出 screenProps,这使我找到了这个解决方案。
您可以像这样设置导航参数:
static navigationOptions = ({ navigation }) => {
return {
tabBarIcon: ({ tintColor, focused }) =>
<View>
<Icon name="bell-ring" size={24} color={focused ? 'green' : 'black'} />
{(navigation.state.params.badgeCount && navigation.state.params.badgeCount > 0) ?
<Text>{navigation.state.params.badgeCount}</Text>
:
<View></View>
}
</View>
}
}
并将 badgeCount 更改为:
this.props.navigation.setParams({ badgeCount: 3 })
在发现 React Navigation 文档的以下部分之前,我一直在努力解决同样的问题并尝试了其他一些答案:https://reactnavigation.org/docs/en/stack-navigator.html#params.
本质上,Stack
中的每个 Screen
都可以传递 params
,其中可以包含处理程序,然后各种屏幕可以与应用程序状态进行交互。
然后我的一般结构是有一个带有状态和处理程序的 App
class,然后根据需要将处理程序传递到每个导航 Screen
。我不确定这个模式是否正确,但这是我理解一般 React 教程的方式。
示例:在我的演示应用程序中,我的页面流如下:
- 公园查找器屏幕 -> 公园详细信息屏幕(带有
Bookmark
操作) - 书签列表屏幕 -> 公园详情屏幕
如果找到公园,可以单击 Bookmark
按钮,将公园添加到书签屏幕上显示的书签列表中。然后您可以单击公园书签查看详细信息。
我的 App
大致是这样的:
import React, { Component } from 'react';
// Screens
import ParkFinderScreen from './Components/ParkFinderScreen';
import ParkBookmarksScreen from './Components/ParkBookmarksScreen';
import ParkDetailsScreen from './Components/ParkDetailsScreen';
// Navigation
import { createStackNavigator, createBottomTabNavigator, createAppContainer } from 'react-navigation';
class App extends Component {
constructor(props) {
super(props);
this.state = {
bookmarks: new Map()
};
}
// Bookmark the park shown in the detail section.
handleBookmark (park) {
let newBookmarks = this.state.bookmarks;
newBookmarks.set(park.parkCode, park);
this.setState({
bookmarks: newBookmarks
});
}
render() {
const FinderStack = createStackNavigator(
{
ParkFinder: {
screen: ParkFinderScreen
},
ParkFinderDetails: {
screen: ParkDetailsScreen,
params: {
handleBookmark: (park) => this.handleBookmark(park),
}
},
}
);
const BookmarksStack = createStackNavigator(
{
ParkBookmarks: {
screen: ParkBookmarksScreen,
params: {
bookmarks: this.state.bookmarks
}
},
ParkBookmarksDetails: {
screen: ParkDetailsScreen,
},
}
);
const AppNavigator = createBottomTabNavigator(
{
Bookmarks: BookmarksStack,
Finder: FinderStack,
}
);
const AppContainer = createAppContainer(AppNavigator);
return (
<AppContainer/>
);
}
}
export default App;
我正在使用 Apollo Client,但我删除了那些部分。
在 Screen
组件中,您可以使用 this.props.navigation.getParam('bookmarks')
.
props
我遇到的一个问题是,每当我更改应用程序状态时,我都会被带到第一个屏幕。状态已更新,但有点迷失方向。我不确定是否有办法在停留在屏幕上的同时更新 App 状态。我可以理解,鉴于 App 状态已更新,所有子项都需要更新,因此当前屏幕(我认为是子项的一部分)将被重置。我不知道这是系统的限制还是我设计组件的副产品。
我希望这对某人有所帮助。这似乎符合 React Native 的预期行为。库团队似乎真的希望你不要使用 Redux。 https://reactnavigation.org/docs/en/redux-integration.html