Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
like image 701
Kid Avatar asked Jul 16 '21 18:07

Kid


People also ask

Should I keep all component's state in Redux store?

Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state. Using local component state is fine.

Is Redux store permanent?

Redux Persist is a popular library which lets you add persistence to the store. The library will automatically save the store each time the state updates. You don't need to write any persistence code in your actions or reducers. You now need to connect the library to your store.

Does Redux cause re render?

​ Even though the array might contain the exact same object references each time, the array itself is a different reference, so the shallow equality check fails and React Redux would re-render the wrapped component.

Does Redux state change cause re render?

React-redux component does not rerender on store state change.

What is the use of store in Redux?

It is used to manage the state of data and access them at different components level in the app. In redux, there are three parts as follows: Store: It is an object which provides the state of the application. This object is accessible with help of the provider in the files of the project.

Does Redux Redux have a dispatcher?

Redux doesn't have a Dispatcher or support many stores. Instead, there is just a single store with a single root reducing function. As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree.

How do I get the current state of a redux store?

React Redux's <Provider> component uses <ReactReduxContext.Provider> to put the Redux store and the current store state into context, and connect uses <ReactReduxContext.Consumer> to read those values and handle updates. The useStore hook returns the current store instance from the default ReactReduxContext.

What is React Redux used for?

React Redux provides APIs that allow your components to dispatch actions and subscribe to data updates from the store. As part of that, React Redux abstracts away the details of which store you are using, and the exact details of how that store interaction is handled.


2 Answers

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

like image 174
marzelin Avatar answered Oct 21 '22 20:10

marzelin


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.

like image 31
Hanan Mehmood Avatar answered Oct 21 '22 20:10

Hanan Mehmood