0

我有Reminder component一个表单,我在其中存储文本和日期 onClick 使用AsyncStorage.

现在,我想在Agenda Component.

我正在使用Agenda componentreact-native-calendarsreact -native-calendars

这是我的reminder component

    class Reminder extends Component {
        constructor(props) {
            super(props);
            this.state = {
                input: '',
                chosenDate: new Date(),
            };
            this.setDate = this.setDate.bind(this);
            this.handleChangeInput = this.handleChangeInput.bind(this);
            this.saveData = this.saveData.bind(this);
        }

        setDate(newDate) {
            this.setState({
                chosenDate: newDate
            });
        }

        handleChangeInput = (text) =>  {
            this.setState({input:text});
        }

        //save the input
        saveData() {
            AsyncStorage.setItem("key", JSON.stringify(this.state));
        }
        render() { 
            return ( 
                <View>
                    <Form style={styles.formContainer}>
                        <View style={styles.formView}>

                                < TextInput
                                placeholder = "Set your reminder"
                                onChangeText={this.handleChangeInput}
                                value={this.state.input}
                                />

                            <DatePicker
                                defaultDate={new Date()}
                                minimumDate={new Date(2018, 1, 1)}
                                maximumDate={new Date(2019, 12, 31)}
                                locale={"en"}
                                timeZoneOffsetInMinutes={undefined}
                                modalTransparent={false}
                                animationType={"fade"}
                                androidMode={"default"}
                                placeHolderText="Select date"
                                textStyle={{ color: "green" }}
                                placeHolderTextStyle={{ color: "#d3d3d3" }}
                                onDateChange={this.setDate}
                            />
                            <Text style={styles.datePicker}>
                                {this.state.chosenDate.toString().substring(0,10)}
                            </Text>
                        </View>
                        <View style={styles.footer}>
                            <Button block success style={styles.saveBtn} 
                            onPress={ () => 
                                {
                                  this.saveData()
                                  console.log('save data',this.state);
                                }
                            } 
                               >
                                <Icon type='MaterialIcons' name='done' />                        
                            </Button>
                        </View>
                    </Form>
                </View> 
            );
        }
    }

export default Reminder;

这是屏幕Reminder screen

import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import PropTypes from 'prop-types';

import Reminder from '../components/Reminder';

const ReminderScreen = ({navigation}) => (
    <View >
        <Reminder navigation={navigation} >
            <StatusBar backgroundColor = "#28F1A6" />
         </Reminder >
    </View>
);

Reminder.propTypes = {
    navigation: PropTypes.object.isRequired
}

export default ReminderScreen;

这是我要显示该数据的组件Agenda Component

class WeeklyAgenda extends Component {
    constructor(props) {
    super(props);
    this.state = {
      items: {},
      selectedDate: ''
    };
  }

  render() {
    return (
      <View style={{height:600}}>
            <Agenda
              items={this.state.items}
              loadItemsForMonth={this.loadItems.bind(this)}
              selected={this.props.day}
              renderItem={this.renderItem.bind(this)}
              renderEmptyData={this.renderEmptyDate.bind(this)}
              rowHasChanged={this.rowHasChanged.bind(this)}
              onRefresh = {() => { this.setState({refeshing : true})}}
              refreshing = {this.state.refreshing}
              refreshControl = {null}
              pastScrollRange={1}
              futureScrollRange = {3}
              theme = {
                {
                  agendaTodayColor: '#28F1A6',
                  agendaKnobColor: '#28F1A6',
                  dotColor: '#28F1A6',
                  selectedDayBackgroundColor: '#28F1A6',
                  todayTextColor: '#28F1A6',
                }
              }
          />
          <View >
              <Fab
                  active={!this.state.active}
                  direction="up"
                  style={{ backgroundColor: '#28F1A6'}}
                  position = 'bottomRight'
                  onPress={() => this.props.navigation.navigate('Reminder')}>
                  <Icon type='MaterialCommunityIcons' name="reminder" />
              </Fab>
          </View>
      </View>
    );
  }

  //On application loads, this will get the already saved data and set the state true when it's true.
    componentDidMount() {
        AsyncStorage.getItem("key").then((newItems) => {
            this.setState(JSON.parse(newItems));
        });
    }

  loadItems = (day) => {
    console.log('day',day);
    console.log('items', this.state.items);
    const {selectedDate} = this.state;

    setTimeout(() => {
      console.log('selected date', selectedDate);
      this.setState({selectedDate: day});
      console.log('selected date later', day);
      const newItems = {};
      Object.keys(this.state.items).forEach(key => {newItems[key] = this.state.items[key];});
      console.log('new items later', newItems);
      this.setState({
        items: newItems
      });
      console.log('new items later', this.state.newItems);
      console.log('items later', this.state.items);
      this.state.items;
    },1000);

  };

  renderItem(item) {
    return (
      <View style={[styles.item, {height: item.height}]}>
        <TouchableOpacity onPress={() => {this.props.navigation.navigate('Reminder')}}>
          <Text>{item.name}</Text>
        </TouchableOpacity>
      </View>
    );
  }

  renderEmptyDate() {
    return (
      <View style={styles.emptyDate}>
        <TouchableOpacity onPress={() => {this.props.navigation.navigate('Reminder')}}>
          <Text style={styles.emptyTextColor}> No Event or Reminder on this date </Text>
        </TouchableOpacity>
      </View>

    );
  }

  rowHasChanged(r1, r2) {
    return r1.name !== r2.name;
  }

  timeToString(time) {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
  }
}

export default WeeklyAgenda;

这是它的屏幕Agenda Screen

import React, { Component } from 'react';
import { View, Text, StatusBar } from 'react-native';
import PropTypes from 'prop-types';

import WeeklyAgenda from '../components/Agenda';
class AgendaScreen extends Component {
    state = {  }
    render() { 
        const {navigation} = this.props;
        const { params } = this.props.navigation.state;
        return (
            <View style={{height: 100}}>     
                <WeeklyAgenda day={params["day"]} navigation={navigation}>
                    <StatusBar backgroundColor="#28F1A6" />
                </WeeklyAgenda >
            </View>
        );
    }
}

WeeklyAgenda.propTypes = {
    navigation: PropTypes.object.isRequired
}

export default AgendaScreen;

我对 react-native 还很陌生,并且仍在尝试弄清楚如何在组件和屏幕之间共享数据。

项目结构

4

2 回答 2

0

所以基本上在组件之间的 react-native 数据流中涉及到 props。如果您需要将一个组件的整个状态传递给另一个组件,您可以通过将状态字符串化来将 props 传递给第二个组件,并通过再次将其解析为 json 对象来接收 props。

如果您使用任何导航在组件和屏幕之间导航,您还可以使用 passProps 将状态发送到下一个屏幕。希望这可以帮助。

于 2018-12-08T19:13:45.703 回答
0

为此,您需要获取您的项目并将它们映射到您的议程组件中。我不知道 item 对象包含什么道具,所以我只是组成了 item.name 和 item.whatever。我也不知道你想如何显示这些数据。您可以在 map 函数的 return 语句中随意显示它。

如果您想要一个表格,只需在 return 语句中呈现一个表格并相应地动态添加您的项目道具。这有意义吗?

此外,map 函数中返回的最外层元素必须有一个仅接受唯一键的 key 道具。

 state = { 
     items: [], 
     selectedDate: ''
 }
  render() {
      const { items } = this.state; // destructure state, so create a variable called items that is equal to this.state.items essentially takes the items in the state variable items and copies them to a new const variable called items
    return (
      <View style={{height:600}}>
            <Agenda
              items={items} //send those items to Agenda Component via prop
              loadItemsForMonth={this.loadItems.bind(this)}
              selected={this.props.day}
              renderItem={this.renderItem.bind(this)}
              renderEmptyData={this.renderEmptyDate.bind(this)}
              rowHasChanged={this.rowHasChanged.bind(this)}
              onRefresh = {() => { this.setState({refeshing : true})}}
              refreshing = {this.state.refreshing}
              refreshControl = {null}
              pastScrollRange={1}
              futureScrollRange = {3}
              theme = {
                {
                  agendaTodayColor: '#28F1A6',
                  agendaKnobColor: '#28F1A6',
                  dotColor: '#28F1A6',
                  selectedDayBackgroundColor: '#28F1A6',
                  todayTextColor: '#28F1A6',
                }
              }
          />
    );
  }

  //On application loads, this will get the already saved data and set the state true when it's true.

    componentDidMount() {
        AsyncStorage.getItem("key").then((newItems) => {
            //assuming JSON.parse returns an array of JSON objects, if not change
            //items to items: {} the way you had it originally in state
            this.setState({ items: JSON.parse(newItems) }) //add the items or data to state variable called items
        });
    }
}

//假设这是您的议程组件

class Agenda extends Component {
    state = { 
        items: this.props.items, //get the items that were passed above using items={item} and assign them to a state variable items here in the Agenda component 
    }

    render() {
        const { items } = this.state; //destructure state
        return(
          <div>
            //put this where you want to render the data in the AgendaComponent you said you were using a Text Component so it would like this
            items.map(item => {
                return (
                  //assuming that item object comes with an id if not you must add a unique key so you can call a func that updates a count variable and returns it
                  <Text key={item.id}>{item.name} {item.date}</Text>
                )
            })
        )
      </div>
    }
}

记住。map 函数几乎就像一个 for 循环。它将遍历数组中的每个元素,并对数组中的每个元素执行 return 语句中的操作。

希望这可以帮助。

更新

我写的以前的解决方案有一个错误。Agenda 组件在实际接收道具之前设置状态,并且在道具更新时没有更新状态。

出于某种原因,componentWillReceiveProps 从来没有得到任何道具。但是,componentDidUpdate 在一次更新后收到了道具。问题是您不能 setState进入,componentDidUpdate()否则您将陷入无限循环。所以这是一个解决方法。如果有人对此有更好的解决方案,请编辑我的答案或发布新答案。

以下内容仅适用于您的议程组件。没有其他需要更新

  1. 首先,从这里更新您的状态声明:

    state = { items: this.props.items, // 使用 items={item} 获取上面传递的项目,并将它们分配给 Agenda 组件中的状态变量 items }

对此:

state = {
    items: null, //changed this to null bc the array gave a nested array later on making it more difficult to traverse through
    haveItems: false //this will be used later to check if there are items available in props to update state
  };
  1. 在你的render()函数中改变这个

    渲染() { 常量 { 项目 } = this.state; //解构状态 return( //把它放在你想在你说你使用文本组件的 AgendaComponent 中呈现数据的地方,所以它会喜欢这个 items.map(item => { return ( //假设项目对象来了如果没有 id,则必须添加唯一键,以便调用更新计数变量并返回它的函数 {item.name} {item.date} ) }) ) } }

对此:

const { items, haveItems } = this.state; //destructure state
    if (this.props.items.length === 0) {
      this.setState({ haveItems: false }); //if there aren't any items in props then you have no items so set haveItems to false
    } else {
      //if you already have items then you already handled those items so do nothing
      if (haveItems) {
      } else {
        //handle the items
        this.setState({
          haveItems: true, //set this to true bc now you have items
          items: this.props.items //set items in state to the items in props, you will get one array with all of your objects 
        });
      }
    }
    return (
      <div>
        <div>
          {haveItems
            {* if you have items then map them the question mark means true, if not display nothing, the colon : means false
            ? items.map(item => {
                return (
                  <ul key={item.id}>
                    <li>{item.name}</li>
                    <li>{item.date}</li>
                  </ul>
                );
              })
            : null}
        </div>
      </div>
    );
  }
}

很抱歉,答案很长,但我希望这是您所需要的。

于 2018-12-08T19:15:36.577 回答