Redux中状态更新缓慢

3

我遇到了一个问题,变量更新比路由更改慢。

当我在例如注册页面遇到错误时,错误会立即显示。当我按返回按钮回到登录页面时,通过一个动作 (在componentWillUnmount上触发"clearErrors") 将错误重置为一个空字符串。问题是,在接收到新的空错误状态之前,我可以在登录页面上短暂地看到错误消息。

ErrorReducer.js

import {
    ERROR,
    CLR_ERROR
} from '../actions/types';

const INIT_STATE = {
    error: ''
};

export default (state = INIT_STATE, action) => {
    switch (action.type) {
        case ERROR:
            return { ...state, error: action.payload };
        case CLR_ERROR:
            return { ...state, error: '' };
        default:
            return state;
    }
};  

错误.js(操作)

import { CLR_ERROR } from './types';

export const clearErrors = () => {
    return (dispatch) => {
        dispatch({ type: CLR_ERROR });
    };
};

LoginForm.js

import React, { Component } from 'react';
import { View } from 'react-native';
import { Actions } from 'react-native-router-flux';
import { connect } from 'react-redux';
import { emailChanged, passwordChanged, loginUser, resetRoute, autoLogin } from '../actions';
import { Button, Input, Message } from './common';

class LoginForm extends Component {

    componentWillUnmount() {
        this.props.resetRoute();
    }

    onEmailChange(text) {
        this.props.emailChanged(text);
    }

    onPasswordChange(text) {
        this.props.passwordChanged(text);
    }

    onButtonPress() {
        this.props.loading = true;
        const { email, password } = this.props;
        this.props.loginUser({ email, password });
    }

    render() {
        return (
            <View
                style={{
                    flex: 1,
                    marginLeft: 10,
                    marginRight: 10,
                    flexDirection: 'column',
                    justifyContent: 'center',
                    alignItems: 'center'
                }}
                keyboardShouldPersistTaps="always"
                keyboardDismissMode="on-drag"
            >

                <Message
                    type="danger"
                    message={this.props.error}
                />

                <Input
                    placeholder="din@email.se"
                    keyboardType="email-address"
                    returnKeyType="next"
                    onChangeText={this.onEmailChange.bind(this)}
                    value={this.props.email}
                    icon="ios-mail"
                />
                <Input
                    secureTextEntry
                    placeholder="ditt lösenord"
                    onChangeText={this.onPasswordChange.bind(this)}
                    value={this.props.password}
                    icon="ios-key"
                    iconSize={22}
                />

                <Button
                    loading={this.props.loading}
                    uppercase
                    color="primary"
                    label="Logga in"
                    onPress={this.onButtonPress.bind(this)}
                />

                <Button
                    fontColor="primary"
                    label="Registrera"
                    onPress={() => Actions.register()}
                />
                <Button
                    fontColor="primary"
                    label="Glömt lösenord"
                    onPress={() => Actions.resetpw()}
                />

            </View>
        );
    }

}

const mapStateToProps = ({ auth, errors }) => {
    const { email, password, loading, token } = auth;
    const { error } = errors;
    return { email, password, error, loading, token };
};

export default connect(mapStateToProps, {
    emailChanged, passwordChanged, loginUser, resetRoute, autoLogin
})(LoginForm);

Message.js(用于显示错误的组件)

import React from 'react';
import { View, Text } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import { colors } from '../style';

export const Message = ({ type, message }) => {
    const style = {
        view: {
            alignSelf: 'stretch',
            flexDirection: 'row',
            justifyContent: 'center',
            alignItems: 'center',
            padding: 20,
            margin: 15,
            backgroundColor: colors[type],
            borderRadius: 3,
            elevation: 5,
            shadowRadius: 5,
            shadowColor: colors.smoothBlack,
            shadowOffset: { width: 2.5, height: 2.5 },
            shadowOpacity: 0.5
        },
        text: {
            color: colors.alternative,
            fontSize: 12,
            alignSelf: 'center',
            flex: 1
        },
        icon: {
            marginRight: 20,
            marginLeft: 0,
            marginTop: 2,
            alignSelf: 'center'
        }
    };
    const getIcon = (iconType) => {
        switch (iconType) {
            case 'info':
                return 'ios-information-circle';
            case 'success':
                return 'ios-checkmark-circle';
            case 'danger':
                return 'ios-alert';
            case 'warning':
                return 'ios-warning';
            default:
                return;
        }
    };
    if (message.length > 0) {
        return (
            <View style={style.view}>
                {(type) ? <Icon name={getIcon(type)} size={20} style={style.icon} /> : null}
                <Text style={style.text}>{message}</Text>
            </View>
        );
    }
    return <View />;
};

我正在使用OnePlus3设备运行生产版本,已删除所有console.logs。

根据我的了解,这应该很快。请问我在这里做错了什么吗?

1个回答

3

如果没有查看您的渲染代码,很难确定原因,但是很可能redux更新状态所需的时间并不会导致缓慢,而是在dispatch完成后React重新渲染UI时变慢 - 可能是因为在转换导航器时它正在忙于重新渲染其他内容。

要保证使用redux-thunk的操作顺序,可以从thunk操作创建者中返回一个Promise,并等待操作被分派后再进行导航:

export const clearErrors = () => {
    return (dispatch) => {
        return new Promise(dispatch({ type: CLR_ERROR }));
    };
};

在您看来,一旦错误被清除,您便可以执行后退导航操作:
// assuming the action creator has been passed
// to the component as props
this.props.clearErrors().then(() => navigator.back());

我的组件中有一些绑定。我最近读到这会使渲染变慢,所以也许就是这个原因。 onChangeText={this.onEmailChange.bind(this)} - Anders Ekman
我怀疑那不是问题所在。人们警告不要在render中使用.bind()的原因是它会创建不必要的函数实例,并可能干扰子组件的shouldComponentUpdate检查。两者都不会导致性能问题,我从未见过有人用真实的基准测试来支持他们声称.bind()会引起缓慢的说法。 - jevakallio
我明白了。我已经更新了我的主要帖子,并添加了更多的代码。LoginForm.js是我要返回的组件,它会短暂地显示<Message/>组件。你介意看一下吗? - Anders Ekman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接