Reaction-native: отправить полное состояние из одного компонента в другой? - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть Reminder component, состоящий из формы, в которой я сохраняю текст и дату при нажатии кнопки, используя AsyncStorage.

Теперь я хочу отобразить эти сохраненные данные в Agenda Component.

Я использую Agenda component из react-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;

Я новичок в реагировании на родной язык и все еще пытаюсь понять, как делиться данными между компонентами и экранами.

project stucture

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Для этого вы хотите взять свои предметы и отобразить их в компоненте повестки дня.Я не знаю, какие реквизиты содержит объект item, поэтому я просто составил item.name и item.whothing.Я также не знал, как вы хотите отобразить эти данные.Вы можете отобразить его так, как вам нравится, в операторе return функции map.

Если вы хотите, чтобы таблица просто отображала таблицу в операторе return и динамически добавляла реквизиты вашего элемента соответственно.Имеет ли это смысл?

Кроме того, самый внешний элемент вашего возврата в функции карты должен иметь ключевую опору, которая принимает только уникальные ключи.

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

запомните.функция карты почти как цикл for.Он будет перебирать каждый элемент в массиве и делать то, что есть в операторе возврата для каждого элемента массива.

Надеюсь, это поможет.

Обновление

В предыдущем решении, которое я написал, была ошибка.Компонент Agenda устанавливал состояние до того, как он фактически получил реквизиты, и не обновлял состояние при обновлении реквизитов.

По какой-то причине componentWillReceiveProps никогда не получал никаких реквизитов.Однако componentDidUpdate получил реквизиты после одного обновления.Проблема в том, что вы не можете setState в componentDidUpdate(), иначе вы получите бесконечный цикл.Так что вот работа вокруг.Если у кого-то есть лучшее решение, пожалуйста, отредактируйте мой ответ или отправьте новый ответ с этим.

Следующее только для вашего компонента повестки дня.Больше ничего не нужно обновлять

  1. Сначала обновите декларацию своего состояния следующим образом:

    state = {items: this.props.items, // получите элементыкоторые были переданы выше, используя items = {item} и назначить их переменным состояния элементов здесь в компоненте Agenda}

этому:

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

В вашей функции render() измените это

render () {const {items} = this.state;// destruct state return (// поместите это туда, где вы хотите визуализировать данные в AgendaComponent, который, как вы сказали, вы используете текстовый компонент, поэтому он хотел бы этот items.map (item => {return (// при условии, что объект item приходитс идентификатором, если нет, вы должны добавить уникальный ключ, чтобы вы могли вызвать функцию, которая обновляет переменную count и возвращает ее {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>
    );
  }
}

Извините за длинный ответ, но я надеюсь, что это то, что вам нужно.

0 голосов
/ 08 декабря 2018

Таким образом, в основном в реактивном потоке данных между компонентами используются реквизиты.В случае, если вам нужно передать все состояние одного компонента другому, вы можете передать реквизит второму компоненту, приведя его в состояние и получив его, снова проанализировав его для объекта json.

Если вы используете какой-либонавигация для навигации между компонентами и экранами, вы также можете использовать passProps для отправки состояния на следующий экран.Надеюсь, это поможет.

...