简体   繁体   中英

Preventing redux store value from being used again in the component

I learn react JavaScript and now I have a question about React Redux .

I have a component that listen to a Redux store value that is galled newTag

Here is the Component:

/*
 * Component handles creating new Tags
 */
class AddTag extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            tagName: '',
            categoryName: '',
        };
    }

    submit = () => {
        const { tagName, categoryName } = this.state;
        const { tagsTag, tagsCategories } = this.props;
        // Test if the tag is already created
        const result = tagsTag.find(tag => tag.name === tagName);
        if (result) {
            if (result.category.name === categoryName.name) console.log('jj');
        }
        const { saveTag } = this.props;
        saveTag(tagName.trim(), categoryName);
    };

    changeCategoryName = categoryName => {
        this.setState({
            categoryName,
        });
    };

    changeTagName = tagName => {
        this.setState({
            tagName,
        });
    };

    render() {
        const { classes, tagsCategories, isSavingNewTagStarted, newTagErrMsg, newTag } = this.props;
        const { tagName, categoryName } = this.state;

        return (
            <Container className={classes.root}>
                <Typography className={classes.typography} gutterBottom variant="h6" align="left">
                    Type the new Tag name and select the Tag category
                </Typography>
                <div>
                    <TextField
                        className={classes.tagTextField}
                        id="outlined-basic"
                        label="New Tag Name"
                        placeholder="New Tag Name"
                        variant="outlined"
                        value={tagName}
                        onChange={e => this.changeTagName(e.target.value)}
                        autoComplete="off"
                        InputProps={{
                            className: classes.inputBackground,
                        }}
                        InputLabelProps={{
                            className: classes.inputLabel,
                        }}
                    />
                    <FormControl>
                        <InputLabel id="category-select">Category</InputLabel>
                        <Select
                            className={classes.selectInput}
                            labelId="category-select"
                            id="demo-simple-select-helper"
                            value={categoryName}
                            onChange={e => this.changeCategoryName(e.target.value)}
                        >
                            {tagsCategories &&
                                tagsCategories.map((element, index) => {
                                    return element.name !== 'All Tags' ? (
                                        <MenuItem value={element} key={element.id}>
                                            {element.name}
                                        </MenuItem>
                                    ) : null;
                                })}
                        </Select>
                    </FormControl>
                    <Button
                        className={classes.button}
                        onClick={() => this.submit()}
                        variant="contained"
                        color="primary"
                        disabled={!tagName || !categoryName}
                    >
                        Save Tag
                    </Button>
                    {newTagErrMsg && <p className="error">{newTagErrMsg.message}</p>}
                    {newTag && <p>New Tag was saved!</p>}
                </div>
                <div>{isSavingNewTagStarted ? <Dots /> : null}</div>
            </Container>
        );
    }
}

const mapDispatchToProps = dispatch => ({
    saveTag: (name, category) => dispatch(saveNewTag(name, category)),
});

const mapStateToProps = state => {
    return {
        tagsCategories: state.global.tagsCategories,
        tagsTag: state.global.tags,
        isSavingNewTagStarted: state.global.isSavingNewTagStarted,
        newTagErrMsg: state.global.newTagErrMsg,
        newTag: state.global.newTag,
    };
};
const enhance = compose(withStyles(styles), connect(mapStateToProps, mapDispatchToProps));
export default enhance(AddTag);

When a new Tag is saved this code line is true:

    {newTag && <p>New Tag was saved!</p>}

problem is that the newTag from Redux store is after the new tag is saved, always true. So this means that the text "New Tag was saved" is then always visible.

I wonder about a way to reset the Redux store newTag so the text "New Tag was saved" is not showed after some render later.

  • should I dispatch a call to the store and setting newTag like 'nothing' (it is not used anywhere else)
  • should I create some localstorage variable to use and test for if newTag is same as before then the "New Tag was saved" will not be showed.

Is there some Redux way method I have missed maybe?

Here is the reduces following well known praxis I think.

import { globalActionTypes } from './global.types';

const INIT_STATE = {
    tags: [],
    tagsCategories: [],

    isSavingNewTagStarted: false,
    newTag: '',
    newTagErrMsg: '',
};

const globalReducer = (state = INIT_STATE, action) => {
    switch (action.type) {
        // SET_TAGS_ADDED
        case globalActionTypes.SET_TAGS:
            return {
                ...state,
                tags: action.payload,
            };
        // SET_TAGS_CATEGORIES
        case globalActionTypes.SET_TAGS_CATEGORIES:
            return {
                ...state,
                tagsCategories: action.payload,
            };
        // ADD_NEW_TAG
        case globalActionTypes.ADD_NEW_TAG_START:
            return {
                ...state,
                isSavingNewTagStarted: true,
            };
        case globalActionTypes.ADD_NEW_TAG_SUCCESS:
            return {
                ...state,
                isSavingNewTagStarted: false,
                newTag: action.payload,
            };
        case globalActionTypes.ADD_NEW_TAG_FAILURE:
            return {
                ...state,
                isSavingNewTagStarted: false,
                newTagErrMsg: action.payload,
            };
        default:
            return state;
    }
};

export default globalReducer;

Just dispatch an action to clear newTag . No need to ruminate over it.

As of good practices, will not recommend changing the redux store for the manipulation of UI of the app. Redux should store data to be displayed.

Solution for the above case can be done in the following way:

  1. Define a new state variable "tagStatus" in the component, which will be set once the new tag is added.
  2. However, timeout here will also be added having a handler that will reset the "tagStatus".

In this way, we are not changing anything in redux and are also able to solve the issue by changing the code on the component level.

try to pass ...state to the default case

default:
  return {
    ...state
  }

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