简体   繁体   中英

How can I force components to re-render without using props or state directly in JSX?

Consider the 3 following JS files (index.js, actions.js and reducer.js) in a react-native application using react-redux .

index.js

import React, {Component} from 'react';
import {View, Text, ActivityIndicator} from 'react-native';
import {connect} from 'react-redux';

import {onSetup} from './actions';

class Scene01 extends Component {

    componentWillMount() {

        // dataFromOtherScene EXISTS when this Scene is created!
        // It is an OBJECT;

        this.props.onSetup(this.props.dataFromOtherScene);

    }

    render () {

        console.log('R', this.props);

        if ((this.props.paths) && (this.props.reference) && (this.props.current >= 0)) {

            const processedData = this.props.reference[Object.keys(this.props.reference)[0]].data;

            const currentPath = this.props.path[this.props.current];

            const pathData = processedData.steps[currentPath[1]].questions[currentPath[2]];

            return (
                <View>
                    <Text>{currentPath.title}</Text>
                    <Text>{pathData.anyProperty}</Text>
                    <Text>{pathData.anotherProperty}</Text>
                </View>
            );

        } else {

            return (
                <ActivityIndicator size='large' />
            );

        }

    }

}

const mapStateToProps = (state) => {
    return {
        ...state.Scene01Reducer,
        dataFromOtherScene: state.OtherScene.data
    };
};
export default connect(mapStateToProps, {
    onSetup
})(Scene01);

actions.js

export const ON_SETUP_SUCCESS_ACTION = 'D8129820-723B-42CE-9C2D-EA0524919E89';
export const onSetup = (data) => {

    const paths = [];
    const reference = data.reference[Object.keys(data.reference)[0]].steps;

    const steps = Object.keys(reference);

    for (let s = 0; s < steps.length; s++) {

        const step = reference[steps[s]];

        const path = [step.title, steps[s]];

        const questions = Object.keys(step.questions);

        for (let q = 0; q < questions.length; q++) {

            const fullpath = [...path, questions[q]];

            paths.push(fullpath);

        }

    }

    return {
        type: ON_SETUP_SUCCESS_ACTION,
        payload: {paths, reference}
    };

};

reducer.js

import {ON_SETUP_SUCCESS_ACTION} from './actions';

/**
 * Default State
 */
const DEFAULT_STATE = {
    current: null,
    paths: null,
    reference: null
};

/**
 * Reducer Body
 */
export default (state = DEFAULT_STATE, action) => {

    switch (action.type) {
        case ON_SETUP_SUCCESS_ACTION:
            return {...state, paths: action.payload.paths, reference: action.payload.reference, current: 0};
        default:
            return state;
    }

};

I tried many approaches... constructor, componentWillReceiveProps, componentShouldUpdate but after the react-redux updates the state ( return {type: ON_SETUP_SUCCESS_ACTION, payload: {paths, reference}}; ), the render method is called again but the } else { statement keeps rendered.

The console.log('R', this.props); shows the first time it is called null for the 3 reducers properties: paths , reference and current .

The second time, after reducer update, the console shows these 3 properties properlly set... but the component does not update... does not re-render.

are you completely sure that your if is with a true value?

(this.props.paths) && (this.props.reference) && (this.props.current >= 0) this could be false and the else statement would always render.

If it is, you could try to use a lifecycle method like componentWillMount or componentWillUpdate.

Also i think that you should use mapStateToProps to send paths, reference and current as a prop.

For this scenario, I decided to move all the "onSetup" code from actions to const mapStateToProps scope and then I remove all react-native component* methods. As I need a start, I removed the paths and reference from the reducer and set then directly in mapStateToProps scope:

index.js

const mapStateToProps = (state) => {

    const paths = [];
    const reference = data.reference[Object.keys(data.reference)[0]].steps;

    const steps = Object.keys(reference);

    for (let s = 0; s < steps.length; s++) {
    ...


    return {
        ...state.Scene01Reducer,
        dataFromOtherScene: state.OtherScene.data,
        paths,
        reference
    };

};

reducer.js

const DEFAULT_STATE = {
    current: 0,
};

actions.js

Deleted!

This worked for me as a solution.

看完您需要的内容后,我认为您应该尝试使用forceUpdate()函数来重新渲染该组件而不使用setState。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM