I'm writing a website in react which displays information on mobile apps and I'm using redux to store the information about the current app. I have an input text field located in the header where the user can type for some app id and if it's a valid id they will be redirected to another page, if the id is not valid a snackbar will be displayed with appropriate message and if the user just hit enter a snackbar will also be displayed with appropriate message. AppNotFound
is the component which wraps snackbar.
I'm using redux thunks to dispatch an action which checks whether the app id is valid (it's an async function) inside onKeyDown
method ( getAppInfo
). Ideally I'd like to get the result from the redux already in onKeyDown
method. But because the action is dispatched asynchronically I can't.
So I thought to let render
display a snackbar based on the value of found
property (whether app was found or not). So at first found
would be undefined
because the async dispatch wouldn't have returned the result in the render
but then found
would become true
or false
and then we can display the snackbar. The render would automatically be called the second time because the props have changed. But this doesn't happen.
What is the correct way in terms of patterns to achieve what I want? I don't want to use componentWillReceiveProps
as it's deprecated.
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import InputBase from '@material-ui/core/InputBase';
import { withStyles } from '@material-ui/core/styles';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { getAppInfo } from '../../actions/appActions.js';
import constants from '../../constants.js';
import { AppSearchBarInputStyles } from '../styles/Material-UI/muiStyles.js';
import AppNotFound from './AppNotFound.js';
import * as log from 'loglevel';
log.setLevel("debug")
class AppSearchBarInput extends Component {
state = {
appId: '',
snackBarOpen: false
}
onChange = e => {
this.setState({ appId: e.target.value });
}
onKeyDown = e => {
const { appId } = this.state;
const { found } = this.props.app;
if (e.keyCode === constants.ENTER_KEY) {
this.props.getAppInfo({ appId });
if (found) {
this.props.history.push('/moreInfo');
} else {
this.setState({
snackBarOpen: true
});
}
this.setState({
appId: ''
});
}
}
handleCloseSnackBar = () => {
this.setState({
snackBarOpen: false
});
}
render() {
const { classes, app } = this.props;
const { snackBarOpen } = this.state;
const { found, appId } = app;
let message = '';
if (!found) {
message = appId === '' ? constants.MESSAGES.APP_BLANK() : constants.MESSAGES.APP_NOT_FOUND(appId);
}
let displayWhenFoundIsUndefined = null;
if (found === undefined) {
displayWhenFoundIsUndefined = <div>Loading...</div>;
} else {
displayWhenFoundIsUndefined = <AppNotFound message={message}
open={!found}
onClose={this.handleCloseSnackBar}/>;
}
return (
<div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
value={this.state.appId} />
{displayWhenFoundIsUndefined}
</div>
)
}
}
AppSearchBarInput.propTypes = {
classes: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
app: state.app.app
});
const AppSearchBarWithStyles = withStyles(AppSearchBarInputStyles)(AppSearchBarInput);
const AppSearchBarWithStylesConnected = connect(mapStateToProps, { getAppInfo })(AppSearchBarWithStyles);
export default withRouter(AppSearchBarWithStylesConnected);
Since no one still didn't answer this question, I will offer the solution which I recently arrived to.
The problem essentially is that the display of AppSearchBarInput
depends mainly on whether the app was found or not. This action must be asynchronic because the information is from Web API. Therefore, I was using redux-thunk
s and was receiving mobile app information in props. However the snackbarOpen
property was in the state which is a problem because the snackbar depends on state property which in itself depends on props which are received asynchronically.
The solution to the predicament is to move snackbarOpen
to props as well. So now an action to set snackbarOpen
to true
should be dispatched directly from getAppInfo
thunk if the app was not found, as well as from onKeyDown
when the app is blank. On the other hand an action to set snackbarOpen
to false should be dispatched from handleCloseSnackBar
.
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.