Markdown Previewer (React + Redux) State issue

Markdown Previewer (React + Redux) State issue
0

#1

Hello everybody!

I am trying to build the Markdown Project by combining react with redux and somehow my textarea field where I enter the Markdown is out of sync with the Preview field. (I haven’t added the marked library yet which I am planning to after fixing this problem)

2018-08-17_12-17-26-1

As you can see in this gif that the div element below the textarea field is always one letter behind the actual input of the textarea field.

My code is:

Reducer

import {SHOW_PREVIEW} from './actions'

debugger;
const editorReducer = (state = "", action) => {
    switch (action.type) {
        case SHOW_PREVIEW:
        return  action.payload
        default:
        return state;
    }
}

export default editorReducer

Action

export const SHOW_PREVIEW = 'SHOW_PREVIEW'

export const showPreview = (text) => {
    return {
    type: SHOW_PREVIEW,
    payload: text
  }
}

Texteditor for entering text

import React, { Component } from 'react';
import './App.css';
import {showPreview} from './actions'
import {connect} from 'react-redux'



class TextEditor extends Component {
    constructor(props) {
        super(props);
        this.state = {
            text: ''
        }
    }

    onTextAreaChange(event) {
        this.setState({
            text: event.target.value
        })
        this.props.showPreview(this.state.text);

    }
    

    render() {
        return (
            <div>
            <textarea id="editor" onChange={this.onTextAreaChange.bind(this)} value={this.state.text}/>
            </div>
        )
    }
}


    
const mapStateToProps = (state) => {
    return {
        text: state.editor}
}



export default connect(mapStateToProps, {showPreview})(TextEditor)

(Previewer to preview text out of textarea element)

import React, { Component } from 'react';
import './App.css';
import {connect} from 'react-redux'


class Previewer extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            
            <div><div id="preview" >{this.props.text}</div></div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        text: state.editor}
}

export default connect(mapStateToProps)(Previewer)

I would apreciate any help regarding this matter:)
Thanks !


#2

Hello.

Without setting up and running your code, it’s hard to say. But one thing did catch my eye.

    onTextAreaChange(event) {
        this.setState({
            text: event.target.value
        })
        this.props.showPreview(this.state.text);

    }

The method setState is asynchronous, so you can not count on this.state being updated by the time this.props.showPreview. There are two possible solutions.

  1. Put your this.props.showPreview call as a second parameter in the this.setState so it will be called as a callback when this.setState is called. It will have to be wrapped in an anonymous function so it doesn’t get invoked automatically.
  2. Use event.target.value in your call to this.props.showPreview.

Just as a note, I don’t know if showPreview is the best name. I would have called it updatePreview. It’s a small thing, but your name confused me for a minute as I was trying to figure out exactly what it is doing. You redux methoid is updating the store and React/Redux is doing the showing, I don’t know, maybe I’m nitpicking.


#3

Yes that is the mistake here. I actually figured it out by myself after spending many hours on it:joy: but I couldn’t come up with an explanation why it didn’t work. After reading your explanation everything makes sense now. Thank you very much !

And yes showPreview is a confusing name, I have to agree with you. I always struggle to come up with meaningful names for my variables/functions …


#4

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton