簡體   English   中英

將數據傳遞給父組件時是否需要抬起 state?

[英]Is it necessary to lift the state up when passing data to parent component?

我正在做我的 react native 項目,我認為我犯了一個大錯誤。 我有一個DaySelector組件,它有一個Day孩子。 他們的目的是創建一個多選欄,顯示一周中的每一天。 這是代碼:

import * as React from "react";
import { View, Text, StyleSheet, Button, Alert } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import colors from "../assets/constants/style-variables";

interface Item {
  selected: Boolean;
  day: String;
}

function Day(props) {
  return (
    <TouchableOpacity
      onPress={props.onPress}
      style={props.selected ? styles.buttonActive : styles.button}
    >
      <Text>{props.day}</Text>
    </TouchableOpacity>
  );
}

export default class DaySelector extends React.Component<
  {},
  { selectedItems: undefined | Item[]; items: Item[] }
> {
  constructor(props) {
    super(props);
    this.state = {
      selectedItems: [],
      items: [
        {
          selected: false,
          day: "Lu",
        },
        {
          selected: false,
          day: "Ma",
        },
        {
          selected: false,
          day: "Mi",
        },
        {
          selected: false,
          day: "Ju",
        },
        {
          selected: false,
          day: "Vi",
        },
        {
          selected: false,
          day: "Sa",
        },
        {
          selected: false,
          day: "Do",
        },
      ],
    };
  }

  onPress = (index) => {
    let items = [...this.state.items];
    let item = { ...items[index] };
    item.selected = !item.selected;
    items[index] = item;
    this.setState({ items });
    this.setState((prevState) => ({
      selectedItems: prevState.items.filter((i) => i.selected),
    }));
  };

  onCompleteSelection = () => {
    console.log(this.state.selectedItems);
  };

  render() {
    return (
      <View>
        <View style={styles.container}>
          {this.state.items.map((item, index) => {
            return (
              <Day
                key={index}
                selected={item.selected}
                day={item.day}
                onPress={this.onPress.bind(this, index)}
              />
            );
          })}
        </View>
        <Button title={"Check"} onPress={this.onCompleteSelection} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flexDirection: "row",
  },
  button: {
    margin: 5,
    borderColor: colors.lightGray,
    borderWidth: 2,
    borderRadius: 40,
    padding: 7,
  },
  buttonActive: {
    margin: 5,
    borderColor: colors.primary,
    borderWidth: 2,
    backgroundColor: colors.primary,
    borderRadius: 50,
    padding: 7,
  },
});

它工作得非常好,抓取數據並將其記錄在控制台中。 但問題是我將這個組件集成到另一個“表單”中,用戶不僅要選擇星期幾,還要選擇一些日程安排。 我需要放置一個“下一步”按鈕來匯總我所有組件抓取的數據。

我最大的是,我唯一能想到的就是將 state 抬起,這將非常復雜,因為父組件是一個功能組件:

import React, { useState } from "react";
import { useMutation } from "@apollo/react-hooks";
import { REGISTER } from "../Queries";
import Loader from "../components/Loader";
import DateTimePicker from "@react-native-community/datetimepicker";
import { View, Button, StyleSheet } from "react-native";
import colors from "../assets/constants/style-variables";
import { TouchableOpacity } from "react-native-gesture-handler";
import PrimaryText from "../assets/constants/PrimaryText";
import DaySelector from "../components/DaySelector";

export default function ScheduleSelect({ navigation, route }) {
  const [loadingRegistration, setLoadingRegistration] = useState(null);

  const [showTimePicker1, setShowTimePicker1] = useState(false);
  const [showTimePicker2, setShowTimePicker2] = useState(false);

  const [time1, setTime1] = useState(null);
  const [time2, setTime2] = useState(null);


  const show1 = () => {
    setShowTimePicker1(true);
  };

  const show2 = () => {
    setShowTimePicker2(true);
  };

  const handleTimePick1 = (event, selectedTime) => {
    setShowTimePicker1(false);
    if (selectedTime !== undefined) {
      setTime1(selectedTime);
    }
  };

  const handleTimePick2 = (event, selectedTime) => {
    setShowTimePicker2(false);
    if (selectedTime !== undefined) {
      setTime2(selectedTime);
    }
  };

  return (
    <View style={styles.container}>
      <PrimaryText fontSize={20} margin={22} textAlign={"center"}>
        Recibirás turnos en estos horarios:
      </PrimaryText>
      <View style={styles.cardHolder}>
        <View style={styles.card}>
          <View style={styles.timeHelper}>
            <PrimaryText textAlign={"center"}>Desde</PrimaryText>
          </View>
          {time1 && (
            <TouchableOpacity onPress={show1}>
              <View style={styles.timeSelected}>
                <PrimaryText textAlign={"center"} fontSize={36}>
                  {`${time1?.getHours()}:${
                    time1.getMinutes() < 10
                      ? "0" + time1.getMinutes()
                      : time1.getMinutes()
                  }`}
                </PrimaryText>
              </View>
            </TouchableOpacity>
          )}
          {!time1 && (
            <TouchableOpacity style={styles.button} onPress={show1}>
              <PrimaryText fontSize={36} letterSpacing={2} textAlign={"center"}>
                --:--
              </PrimaryText>
            </TouchableOpacity>
          )}
          {showTimePicker1 && (
            <DateTimePicker
              value={new Date()}
              testID="dateTimePicker"
              mode={"time"}
              is24Hour={true}
              display="default"
              onChange={handleTimePick1}
            />
          )}
        </View>
        <PrimaryText fontSize={36} margin={7}>
          -
        </PrimaryText>
        <View style={styles.card}>
          <View style={styles.timeHelper}>
            <PrimaryText textAlign={"center"}>Hasta</PrimaryText>
          </View>
          {time2 && (
            <TouchableOpacity onPress={show2}>
              <View style={styles.timeSelected}>
                <PrimaryText textAlign={"center"} fontSize={36}>
                  {`${time2?.getHours()}:${
                    time2.getMinutes() < 10
                      ? "0" + time2.getMinutes()
                      : time2.getMinutes()
                  }`}
                </PrimaryText>
              </View>
            </TouchableOpacity>
          )}
          {!time2 && (
            <TouchableOpacity style={styles.button} onPress={show2}>
              <PrimaryText fontSize={36} letterSpacing={2} textAlign={"center"}>
                --:--
              </PrimaryText>
            </TouchableOpacity>
          )}
          {showTimePicker2 && (
            <DateTimePicker
              value={new Date()}
              testID="dateTimePicker"
              mode={"time"}
              is24Hour={true}
              display="default"
              onChange={handleTimePick2}
            />
          )}
        </View>
      </View>
      {time2?.getTime() < time1?.getTime() && (
        <PrimaryText color={colors.warning}>
          Por favor, seleccioná horarios válidos
        </PrimaryText>
      )}
      <PrimaryText margin={5}> Los días: </PrimaryText>
      <View style={styles.card}>
        <DaySelector />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    width: "100%",
    height: "100%",
    justifyContent: "center",
    alignItems: "center",
  },
  button: {
    padding: 7,
  },
  card: {
    flexDirection: "row",
    justifyContent: "center",
    backgroundColor: colors.iceWhite,
    borderRadius: 10,
    padding: 20,
    marginBottom: 10,
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
    elevation: 5,
  },
  cardHolder: {
    flexDirection: "row",
    alignItems: "center",
  },
  timeHelper: {
    justifyContent: "center",
    position: "absolute",
    marginTop: 5,
  },
  timeSelected: {
    alignItems: "center",
    justifyContent: "center",
  },
  editIcon: {
    right: 3,
    top: 3,
    position: "absolute",
  },
});

如您所見,它是一個非常大的組件,更糟糕的是,我必須將其設為 class 組件或嘗試將所有內容轉換為功能組件。 有什么辦法可以避免抬起 state 並將數據傳遞給父級?

只需創建一個回調 function 並將其傳遞給您的DaySelector組件,以便您可以將值存儲在父 state

在你的父母

const handleChange = (value) => {
  setDay(value);
}
<DaySelector onChange={handleChange} />

在你的孩子

onCompleteSelection = () => {
  this.props.onChange(this.state.selectedItems);
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM