0

I am trying to implement a green, or red glow on a row depending if a number increases or decreases.

What is the best way to accomplish this?

Is there a way on mapStateToProps or during render to compare the two?

Tiago Bértolo
  • 3,874
  • 3
  • 35
  • 53

3 Answers3

3

Since the component's render-method only has access to the current props and state, you must keep information about how value changed in the current props and/or state. You must then indicate the change for (I assume) a brief amount of time.

Where to set state so we know which color to show

There are several possibilities of where to do this listed below; pick one of them, not all. They all use the following utility fuction:

function getChange(value, prevValue) {
    if (typeof prevValue === 'undefined') {
        // If previos value did not exist, don't count it as a change.
        // This is to avoid "feedback" the first time the value is rendered.
        return;
    }
    if (value === prevValue) {
        return;
    }

    return value < prevValue
        ? 'decrease'
        : 'increase';
}

1. In action creator

Read current state before disptatching an action. Note that this example requires you to use redux-thunk:

const changeValueTo = (value) => (dispatch, getState) => {
    const prevValue = getState().value;

    distpatch({
        type: 'SET_VALUE',
        change: getChange(value, prevValue),
        value: value
    });
}

2. In reducer

function valueReducer(state = { value: void 0, change: void 0 }, action) {
    switch (action.type) {
        case 'SET_VALUE':
            return {
                value: action.value,
                change: getChange(action.value, state.value)
            };
        default:
            return state;
    }
}

PS: void 0 is just a safe way to get undefined.
PPS: We could just use state = {}, but I prefer to be specific.

3. In component's getDerivedStateFromProps

class Value extends React.Component {

    state = {
        change: 'black'
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        return {
            value: nextProps.value,
            change: getChange(nextProps.value, prevState.value)
        };
    }

    render() {
        ...
    }
}

4. In other component lifecycle methods

Like e.g. in componentDidUpdate as suggested by Bruno Mazzardo.

Render color briefly

Here I change the color of the text, but you can of course change the background or anything else.

/* css */
@keyframes red-fadeout {
    from {
        color: red;
    }
    to {
        color: black;
    }
}
@keyframes green-fadeout {
    from {
        color: green;
    }
    to {
        color: black;
    }
}
.decreased {
    animation: 3s red-fadeout;
}
.increased {
    animation: 3s green-fadeout;
}
// React
class Value extends React.Component {
    ...
    render() {
        const {
            value,
            change = '' // Assuming change is either 'increased', 'decreased' or falsy
        } = this.props;

        return (
            <div className={change}>{value}</div>
        );
    }
}
ArneHugo
  • 6,051
  • 1
  • 26
  • 47
  • You are supposed to choose one of the approaches, not all of them. I will update my answer to make that clearer. For this exact case they are all OK, but in different situations it can be useful to know about the various options in case some fit the use case better than others. – ArneHugo May 22 '18 at 17:52
  • Yeah, as he asked for a generic way, I think your answer is the right one. – Bruno Mazzardo May 22 '18 at 17:57
1

You can use componentDidUpdate(prevProps, prevState), make the check inside it, accessing this.props and this.state, that will be updated, and based on that, setState({changed:this.props.number !== this.prevProps.number })

React documentation about lifecycle https://reactjs.org/docs/react-component.html#componentdidupdate for reference

Bruno Mazzardo
  • 1,586
  • 1
  • 15
  • 27
0

You can use this.

this.setState((prevState, props) => {
  if(props.step < 0)
  {
    return {counter: prevState.counter + props.step, color:'red'};
  }
  return {counter: prevState.counter + props.step, color:'blue'};
});

Based on this color in state component will render again. For more info visit. setState

Akshay Garg
  • 80
  • 1
  • 3