让我们尝试绘制一个完整的界面。 我们使用本机库中的组件重写App.js:
import React from 'react'; import {Container, Content} from 'native-base'; import {StyleSheet, Text, View} from 'react-native'; import AppFooter from './components/AppFooter.js'; const styles = StyleSheet.create({ container: { padding: 20 }, }); const App = () => ( <Container> <Content> <View style={styles.container}> <Text> Lorem ipsum... </Text> </View> </Content> <AppFooter/> </Container> ); export default App;
我们看到了必须创建的新AppFooter组件。 我们转到./components/文件夹并创建具有以下内容的AppFooter.js文件:
import React from 'react'; import {Footer, FooterTab, Button, Text} from 'native-base'; const AppFooter = () => ( <Footer> <FooterTab> <Button active> <Text></Text> </Button> <Button> <Text></Text> </Button> </FooterTab> </Footer> ); export default AppFooter;
一切准备就绪,可以尝试构建我们的应用程序!
我们的按钮尚不知道如何切换。 是时候教他们了。 为此,您需要做两件事:学习如何处理click事件以及如何存储状态。 让我们从状态开始。 由于我们选择了纯组件和全局存储,因此拒绝将状态存储在组件中,因此我们将使用Redux。
首先,我们必须创造自己的一面。
import {createStore} from 'redux'; const initialState = {}; const store = createStore(reducers, initialState);
让我们为减速器创建一个空白。 在reducers文件夹中,创建具有以下内容的index.js文件:
export default (state = [], action) => { switch (action.type) { default: return state } };
将reducer连接到App.js:
import reducers from './reducers';
现在,我们需要在组件上分发我们的存储。 这是专门使用提供程序组件完成的。 我们将其连接到项目:
import {Provider} from 'react-redux';
并将所有组件包装在提供程序中。 更新后的App.js如下所示:
import React from 'react'; import {Container, Content} from 'native-base'; import {StyleSheet, Text, View} from 'react-native'; import AppFooter from './components/AppFooter.js'; import {createStore} from 'redux'; import {Provider} from 'react-redux'; import reducers from './reducers'; const initialState = {}; const store = createStore(reducers, initialState); const styles = StyleSheet.create({ container: { padding: 20 }, }); const App = () => ( <Provider store={store}> <Container> <Content> <View style={styles.container}> <Text> Lorem ipsum... </Text> </View> </Content> <AppFooter/> </Container> </Provider> ); export default App;
现在,我们的应用程序可以存储其状态。 让我们利用这一点。 我们添加了模式状态,默认情况下设置为ARTICLES。 这意味着在第一个渲染中,我们的应用程序将设置为显示文章列表。
const initialState = { mode: 'ARTICLES' };
不错,但是手动写入字符串值会导致潜在的错误。 让我们获取常量。 创建具有以下内容的./constants/index.js文件:
export const MODES = { ARTICLES: 'ARTICLES', PODCAST: 'PODCAST' };
并重写App.js:
import {MODES} from './constants'; const initialState = { mode: MODES.ARTICLES };
好吧,有一个状态,是时候将其传递给页脚组件了。 让我们再看看我们的./components/AppFooter.js:
import React from 'react'; import {Footer, FooterTab, Button, Text} from 'native-base'; const AppFooter = () => ( <Footer> <FooterTab> <Button active> <Text></Text> </Button> <Button> <Text></Text> </Button> </FooterTab> </Footer> ); export default AppFooter;
如我们所见,开关的状态是使用Button组件的active属性确定的。 让我们将应用程序的当前状态推送到Button。 这并不困难,引擎盖的主要组件是我们之前连接的Provider组件。 仅保留其中的当前状态并将AppFooter组件放入属性(props)中。 首先,我们修改AppFooter,以便可以通过将模式传递给props来控制按钮的状态:
import React from 'react'; import {Footer, FooterTab, Button, Text} from 'native-base'; import {MODES} from "../constants"; const AppFooter = ({mode = MODES.ARTICLES}) => ( <Footer> <FooterTab> <Button active={mode === MODES.ARTICLES}> <Text></Text> </Button> <Button active={mode === MODES.PODCAST}> <Text></Text> </Button> </FooterTab> </Footer> ); export default AppFooter;
现在让我们开始创建一个容器。 创建文件./containers/AppFooterContainer.js。
import React from 'react'; import AppFooter from '../components/AppFooter.js'; import {MODES} from "../constants"; const AppFooterContainer = () => ( <AppFooter mode={MODES.ARTICLES} /> ); export default AppFooterContainer;
并在App.js中而不是AppFooter组件中连接AppFooterContainer容器。 到目前为止,我们的容器与组件没有什么不同,但是一旦我们将其连接到应用程序的状态,一切都会改变。 开始吧!
import React from 'react'; import AppFooter from '../components/AppFooter.js'; import {connect} from 'react-redux'; const mapStateToProps = (state) => ({ mode: state.mode }); const AppFooterContainer = ({mode}) => ( <AppFooter mode={mode} /> ); export default connect( mapStateToProps )(AppFooterContainer);
很实用! 所有功能都变得干净了。 这是怎么回事 我们使用connect函数将容器连接到状态,并使用mapStateToProps函数将其道具连接到全局状态的内容。 很干净漂亮。
因此,我们已经学会了从上到下分发数据。 现在我们需要学习如何从下至上改变我们的全球状态。 动作旨在生成有关需要更改全局状态的事件。 让我们创建一个单击按钮时发生的动作。
创建文件./actions/index.js:
import { SET_MODE } from './actionTypes'; export const setMode = (mode) => ({type: SET_MODE, mode});
还有./actions/actionTypes文件,我们将在其中存储带有动作名称的常量:
export const SET_MODE = 'SET_MODE';
该操作将创建一个具有事件名称和该事件附带的数据集的对象,仅此而已。 现在,我们将学习如何生成此事件。 我们返回到AppFooterContainer容器并连接mapDispatchToProps函数,该函数会将事件分发程序连接到容器的prop。
import React from 'react'; import AppFooter from '../components/AppFooter.js'; import {connect} from 'react-redux'; import {setMode} from '../actions'; const mapStateToProps = (state) => ({ mode: state.mode }); const mapDispatchToProps = (dispatch) => ({ setMode(mode) { dispatch(setMode(mode)); } }); const AppFooterContainer = ({mode, setMode}) => ( <AppFooter mode={mode} setMode={setMode} /> ); export default connect( mapStateToProps, mapDispatchToProps )(AppFooterContainer);
好吧,我们有一个引发SET_MODE事件的函数,我们将其跳过了AppFooter组件。 仍然存在两个问题:
没有人调用此功能。
没有人在听事件。
我们将处理第一个问题。 我们转到AppFooter组件,并将调用连接到setMode函数。
import React from 'react'; import {Footer, FooterTab, Button, Text} from 'native-base'; import {MODES} from "../constants"; const AppFooter = ({mode = MODES.ARTICLES, setMode = () => {}}) => ( <Footer> <FooterTab> <Button active={mode === MODES.ARTICLES} onPress={ () => setMode(MODES.ARTICLES)}> <Text></Text> </Button> <Button active={mode === MODES.PODCAST} onPress={ () => setMode(MODES.PODCAST)}> <Text></Text> </Button> </FooterTab> </Footer> ); export default AppFooter;
现在,当按下按钮时,将引发SET_MODE事件。 有待学习如何在出现时改变全球状态。 我们转到先前创建的./reducers/index.js并为此事件创建一个reducer:
import { SET_MODE } from '../actions/actionTypes'; export default (state = [], action) => { switch (action.type) { case SET_MODE: { return Object.assign({}, state, { mode: action.mode }); } default: return state } };
太好了! 现在,单击按钮将生成一个更改全局状态的事件,并且页脚在收到这些更改后将重新绘制按钮。