简体   繁体   中英

Dispatch redux action in callback

I have started working with redux in react-native and I encountered problem, when I am dispatching action in onLoadStart function for Image component, the callback is firing and I see that action is called and I see Loading... on screen, but when I am dispatching in onLoadEnd function nothing happen (callback loadEnd is not fired, app looks like frozen) . When I use console.log in both places code is working fine. Could someone tell me what am I doing wrong?

 class DisplayImage extends Component {

    loadStart() {
      this.props.iLoadingFunction(true);
    }
    loadEnd() {  // <- this function is not fired
      this.props.iLoadingFunction(false);
    }

    render() {
        if (this.props.isLoading) {
            return <Text>Loading…</Text>;
        }
        return (
          <View>
              <Image
                source={{uri: 'https://test.com/image'}}
                onLoadStart={this.loadStart.bind(this)}
                onLoadEnd={this.loadEnd.bind(this)}
               />
          </View>
        );
    }
}

const mapStateToProps = (state) => {
    return {
        isLoading: state.isLoading
    };
};
const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({ iLoadingFunction }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(DisplayImage);

action and reducer

export function iLoadingFunction(bool) {
    return {
        type: 'IS_LOADING',
        isLoading: bool
    };
}

export function iLoadingFunction(state = false, action) {
    switch (action.type) {
        case 'IS_LOADING':
            return action.isLoading;
        default:
            return state;
    }
}

I think the issue is coming from the order that actions and renders are occurring in. Let's look at the render function:

render() {
    if (this.props.isLoading) {
        return <Text>Loading…</Text>;
    }
    return (
      <View>
          <Image
            source={{uri: 'https://test.com/image'}}
            onLoadStart={this.loadStart.bind(this)}
            onLoadEnd={this.loadEnd.bind(this)}
           />
      </View>
    );
}

The first time the component mounts this.props.isLoading is false , so the component renders

<View>
    <Image
      source={{uri: 'https://test.com/image'}}
      onLoadStart={this.loadStart.bind(this)}
      onLoadEnd={this.loadEnd.bind(this)}
     />
</View>

The Image mounts, begins loading the image and dispatches this.props.iLoadingFunction(true) .

At this point isLoading updates in the store are triggers a re-render of the component. This time this.props.isLoading is true so the component renders

<Text>Loading…</Text>

Now the original Image has been removed from the hierarchy. I'm not actually sure if it continues to download the image, but the onLoadEnd handler does not fire as the component expecting to handle it has been removed.

To get around this, I would leave the Image in the hierarchy and just include or exclude the Text based on this.props.isLoading , like so

render() {
    return (
      <View>
          { this.props.isLoading && <Text>Loading…</Text> }
          <Image
            source={{uri: 'https://test.com/image'}}
            onLoadStart={this.loadStart.bind(this)}
            onLoadEnd={this.loadEnd.bind(this)}
           />
      </View>
    );
}

The best solution to use callbackable-actions standardized actions. I recommend using the redux-cool package to do that

npm install redux-cool
import {actionsCreator} from "redux-cool"
const callback = () => {
    console.log("Hello, I am callback!!!")
}
const callbackable_action = actionsCreator.CALLBACKABLE.EXAMPLE(1, 2, 3, callback)
console.log(callbackable_action)
//      {
//          type: "CALLBACKABLE/EXAMPLE",
//          args: [1, 2, 3],
//          cb: [[Function callback]],
//          _index: 1
//      }
callbackable_action.cb()
//      "Hello, I am callback!!!"

for more info, see: Redux Cool

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