【问题标题】:How do I render a React Native component using Async Storage data on start up?如何在启动时使用异步存储数据渲染 React Native 组件?
【发布时间】:2018-04-05 05:24:20
【问题描述】:

我想从 AsyncStorage 加载并在我的 react 本机组件渲染期间使用它,但我的组件在应用启动时立即渲染,并且没有给 AsyncStorage 时间返回数据。

如何使用 AsyncStorage 以便我的组件要么 A)等待呈现,直到它们具有正确的信息,要么 B)在加载数据后更改以反映正确的信息?

    import React from 'react';
    import { AsyncStorage } from 'react-native';

    // my wrapper object around AsyncStorage
    export default class StorageManager  {

    constructor() {
        this.data = {
            settings: { },
        }
        this.loadSettings();
    }

    async loadSettings() {
        await AsyncStorage.getItem('settings')
            .then( (settings) => this.data.settings = JSON.parse(settings) )
            .catch( (err) => console.log(err) );
    }

    /*
     * settings = {days: number, currency: string, costPerDay: number }
     */
    getDays() {
        return this.data.settings.days;
    }
}

还有我的组件代码。在这里,AchievementScreen 先渲染,StorageManager 没有时间加载任何内容。其他屏幕会在我切换到它们时呈现,因此它们已正确加载所有内容。

import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Alert} from 'react-native';
import { Container, Header, Content, Body, List, Text} from 'native-base';
import { Col, Row, Grid } from "react-native-easy-grid";
import AchievementCard from '../../components/AchievementCard/AchievementCard'

export default class AchievementScreen extends Component {
    constructor(props) {
        super(props);
        // debugger shows props.storageManager as well-shaped but empty.
        this.state = {
            storageManager: this.props.storageManager,
            achievementCards: [ this.moneySavedAchievement(props.storageManager),
                               {header: "Header 2", body: "Body 2", icon: "money"},
                            ]
        }
    }

    moneySavedAchievement(storageManager) {
        return {
            header: "Money Saved",
            body:   storageManager.data.settings.currency + 
                    storageManager.data.settings.costPerDay *
                    storageManager.data.settings.days,
            icon: "money"
        }
    }

    render() {
        return (
            <Container>
            <Content>
            <Grid>
                <Col>
                    <List   dataArray={this.state.achievementCards.slice(0, this.state.achievementCards.length / 2)}
                            renderRow={ (item) => 
                                <AchievementCard achievementHeader={item.header}
                                    achievementBody={item.body}
                                    achievementIcon={item.icon} />
                            }
                    />
                </Col>
                <Col>
                    <List   dataArray={this.state.achievementCards.slice(this.state.achievementCards.length / 2)}
                            renderRow={ (item) => 
                                <AchievementCard achievementHeader={item.header}
                                    achievementBody={item.body}
                                    achievementIcon={item.icon} />
                            }
                    />
                </Col>
            </Grid>
            </Content>
        </Container>
    );
    }
}

AppRegistry.registerComponent('AchievementScreen', () => AchievementScreen);

我的首页应用代码

import React, {Component} from 'react';
import {AppRegistry, StyleSheet} from 'react-native';
import {Tabs, Tab, Container, Header, Title, Body, TabHeading, Text, Right, Left, Button, TouchableOpacity} from 'native-base';
import Icon from 'react-native-vector-icons/FontAwesome';

import HomeScreen from './app/screens/HomeScreen/HomeScreen';
import MilestoneScreen from './app/screens/MilestoneScreen/MilestoneScreen';
import AchievementScreen from './app/screens/AchievementScreen/AchievementScreen';
import StorageManager from "./app/modules/StorageManager/StorageManager";

export default class my_react_app extends Component {
    constructor() {
        super();
        this.state = {
            storageManager: new StorageManager()
        }
    }

    render() {
        return (
            <Container>
            <Header hasTabs>
            <Left />
                <Body>
                    <Title>My App</Title>
                </Body>
                <Right>
                    <Icon active name="ellipsis-v" color="white"/>
                </Right>
            </Header>
            <Tabs initialPage={0}>
                <Tab heading="Status">
                    <AchievementScreen storageManager={this.state.storageManager} />
                </Tab>
                <Tab heading="Progress">
                    <HomeScreen storageManager={this.state.storageManager} />
                </Tab>
                <Tab heading="Milestones">
                    <MilestoneScreen storageManager={this.state.storageManager} />
                </Tab>
            </Tabs>
            </Container>
        );
    }
}

AppRegistry.registerComponent('my_react_app', () => My_React_App);

【问题讨论】:

    标签: javascript android reactjs asynchronous react-native


    【解决方案1】:

    我可以看到的一个直接问题是AchievementScreen 组件依赖于 storageManager,因此组件可以重新渲染(从外部效果)的唯一方法是如果 storageManager 道具发生变化,这不会发生.

    这一行 -

    <AchievementScreen storageManager={this.state.storageManager} />
    

    此外,如果您希望AchievementScreen 在数据获取时重新呈现,更好的设计是将数据传递给AchievementScreen,而不是传递反过来获取数据的对象。 AchievementScreen 应该不知道从哪里获取数据。 (为了更好地管理副作用,请查看 redux、redux-thunk、redux-saga 等库)

    所以你的理想实现应该是 -

    componentDidMount(){
      this.storageManager.getData().then((data) => 
       this.setState({moneySavedAchievement: data});
     );
    }
    
    <AchievementScreen moneySavedAchievement={moneySavedAchievement} />
    

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      就像您在问题中所说的那样,您的成就屏幕组件在 storageManager 检索数据之前被呈现。您实际上是在构造函数中明确设置状态:

      this.state = { storageManager: this.props.storageManager }

      这设置了this.state.storageManager的值,当storageManager有更新数据时,AchievementScreen组件不知道怎么处理它。

      你可以在你的组件中添加一个componentWillReceiveProps 生命周期钩子,每次你的组件收到新的道具时都会调用这个钩子。所以,你可以这样做:

      在AchievementScreen - 构造函数下:

      componentWillReceiveProps(nextProps) {
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-06
        • 2021-12-13
        • 1970-01-01
        • 1970-01-01
        • 2018-05-14
        • 2018-12-24
        • 1970-01-01
        相关资源
        最近更新 更多