如何在第一次使用 React Hooks 渲染时使用 props 加载子组件

She*_*ixt 5 reactjs react-native redux react-redux

在我的 React Native 项目中,我在功能组件中使用 React Hooks 来设置我的 Redux 存储上的状态。然后我试图通过prop调用的方式将来自商店的值传递给子组件timestamp

问题是,子组件利用了DateTimePicker组件( from react-native-modal-datetime-picker),并且当它最初呈现timestampprop 时未定义,这会导致它出错。结果可以通过以下控制台日志看到:

undefined
undefined
Object {
  "date": "2019-08-20",
  "full": 2019-08-20T12:21:52.874Z,
  "time": "01:21:52",
}
Object {
  "date": "20.08.2019",
  "time": "01:21 pm",
}
Run Code Online (Sandbox Code Playgroud)

组件被渲染两次。首先,道具是未定义的,然后它们被填充。

如何强制props在第一次渲染之前加载?

我不想直接在子组件中调用状态,因为这将在各种用例中重复使用。

这是父组件:

import React, { useEffect } from 'react';
import { View } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import DateInput from '../../../components/DateTimeInput';
import * as actions from '../../../redux/actions';
import moment from 'moment';

const ReportParamsScreen = props => {
    const report        = useSelector(state => state.report);
    const dispatch = useDispatch();

    useEffect(() => { 
        dispatch(actions.setReportParams({ 
            start_date  : moment().subtract(30, "days"),
            end_date    : moment()
        }))
    }, [dispatch]);

    return (
        <View style={styles.row}>
            <View style={styles.column}>
                <DateInput 
                    mode="date"
                    timestamp={report.params.start_date}
                />
            </View>
            <View style={styles.column}>
                <DateInput 
                    mode="date"
                    timestamp={report.params.start_date}
                />
            </View>
        </View>
    )
};

export default ReportParamsScreen;
Run Code Online (Sandbox Code Playgroud)

这是子组件:

import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Body, Button, Text, Icon } from "native-base";
import DateTimePicker from "react-native-modal-datetime-picker";

const DateInput = props => {
    const [isPickerVisible, setIsPickerVisible] = useState(false);

    const showDateTimePicker = () => {
        setIsPickerVisible(true);
    };

    const hideDateTimePicker = () => {
        setIsPickerVisible(false);
    };

    const handleDateTimePicked = dateTime => {
        console.log(dateTime)
        hideDateTimePicker();
    };

    console.log(props.timestamp.value);
    console.log(props.timestamp.labels); // These are the logs referened above.

    return (
        <Body>
            <Button transparent onPress={showDateTimePicker}>
                <Icon
                    type="MaterialIcons"
                    name={props.mode == 'time' ? 'access-time' : 'date-range' }
                />
                <Text>{props.timestamp.labels[props.mode]}</Text>
            </Button>
            <DateTimePicker
                date={props.timestamp.value.date}
                mode={props.mode}
                isVisible={isPickerVisible}
                onConfirm={handleDateTimePicked}
                onCancel={hideDateTimePicker}
            />
        </Body>
    );
}

export default DateInput;
Run Code Online (Sandbox Code Playgroud)

Fue*_*ter 4

在这种情况下,您有两种解决方案,这两种解决方案都取决于哪种解决方案更适合您或您的项目。

\n\n

第一个解决方案是将start_date和设置end_date为有关报告的减速器的初始状态,但我不知道这对您的业务/规则是否有意义,不是最好的解决方案,但该解决方案“更简单”。

\n\n
import React, { useEffect } from \'react\';\nimport { View } from \'react-native\';\nimport { useSelector, useDispatch } from \'react-redux\';\nimport DateInput from \'../../../components/DateTimeInput\';\nimport * as actions from \'../../../redux/actions\';\nimport moment from \'moment\';\n\nconst ReportParamsScreen = props => {\n    const report        = useSelector(state => state.report);\n    const dispatch = useDispatch();\n\n    useEffect(() => { \n        dispatch(actions.setReportParams({ \n            start_date  : moment().subtract(30, "days"),\n            end_date    : moment()\n        }))\n    }, [dispatch]);\n\n    if (!report.params.start_date) {\n      return null\n    }\n\n    return (\n        <View style={styles.row}>\n            <View style={styles.column}>\n                <DateInput \n                    mode="date"\n                    timestamp={report.params.start_date}\n                />\n            </View>\n            <View style={styles.column}>\n                <DateInput \n                    mode="date"\n                    timestamp={report.params.start_date}\n                />\n            </View>\n        </View>\n    )\n};\n\nexport default ReportParamsScreen;\n
Run Code Online (Sandbox Code Playgroud)\n\n

第二种解决方案是验证report.params.start_date上是否未定义ReportParamsScreen,如果为 true,则在日期为 null 时在组件上返回 null 或返回表示 like 的组件Loading,是一个很好的做法。

\n\n

例子:

\n\n
import React, { useEffect } from \'react\';\nimport { View } from \'react-native\';\nimport { useSelector, useDispatch } from \'react-redux\';\nimport DateInput from \'../../../components/DateTimeInput\';\nimport * as actions from \'../../../redux/actions\';\nimport moment from \'moment\';\n\nconst ReportParamsScreen = props => {\n    const report        = useSelector(state => state.report);\n    const dispatch = useDispatch();\n\n    useEffect(() => { \n        dispatch(actions.setReportParams({ \n            start_date  : moment().subtract(30, "days"),\n            end_date    : moment()\n        }))\n    }, [dispatch]);\n\n    if (!report.params.start_date) {\n      return <Loading />\n    }\n\n    return (\n        <View style={styles.row}>\n            <View style={styles.column}>\n                <DateInput \n                    mode="date"\n                    timestamp={report.params.start_date}\n                />\n            </View>\n            <View style={styles.column}>\n                <DateInput \n                    mode="date"\n                    timestamp={report.params.start_date}\n                />\n            </View>\n        </View>\n    )\n};\n\nexport default ReportParamsScreen;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种情况曾经发生过,因为useEffect只在渲染后执行。

\n\n

参考:

\n\n
\n

useEffect 有什么作用?通过使用这个 Hook,您可以告诉 React 您的组件需要在渲染后执行某些操作。React 会记住您传递的函数(我们将其称为 \xe2\x80\x9ceffect\xe2\x80\x9d),并在执行 DOM 更新后调用它。在这种效果中,我们设置了文档标题,但我们也可以执行数据获取或调用其他命令式 API。

\n
\n\n

链接: https: //reactjs.org/docs/hooks-effect.html

\n