Skip to content

Instantly share code, notes, and snippets.

@erikras
Created October 28, 2016 12:23
Show Gist options
  • Save erikras/5ca8dc618bae5dbc8faf7d2324585d01 to your computer and use it in GitHub Desktop.
Save erikras/5ca8dc618bae5dbc8faf7d2324585d01 to your computer and use it in GitHub Desktop.
Using react-rte with redux-form
import React, { Component, PropTypes } from 'react'
class RichTextMarkdown extends Component {
static propTypes = {
input: PropTypes.shape({
onChange: PropTypes.func.isRequired,
value: PropTypes.string
}).isRequired
}
constructor(props) {
super(props)
this.state = { value: undefined }
}
componentDidMount() {
this.RichTextEditor = window.RichTextEditor
this.setState({
value: this.props.input.value ?
this.RichTextEditor.createValueFromString(this.props.input.value, 'markdown') :
this.RichTextEditor.createEmptyValue()
})
}
handleChange = value => {
this.setState({ value })
let markdown = value.toString('markdown')
if(markdown.length === 2 && markdown.charCodeAt(0) === 8203 && markdown.charCodeAt(1) === 10) {
markdown = ''
}
this.props.input.onChange(markdown)
}
render() {
const { RichTextEditor, state: { value }, handleChange } = this
return RichTextEditor ? <RichTextEditor value={value} onChange={handleChange}/> : <div/>
}
}
export default RichTextMarkdown
@AlmasAskarbekov
Copy link

AlmasAskarbekov commented Oct 17, 2017

@cantuket Hey,
recently got solved almost the same issue
this solution probably solve your's:

<Field
      component={RichTextField}
       type="text" 
       name="overview"
       input={{ value: whateverState || yourValue, onChange:(value)=> value.toString('html') }}
/>

there are the Shape proptype in subj gist:

  static propTypes = {
    input: PropTypes.shape({
      onChange: PropTypes.func.isRequired,
      value: PropTypes.string
    }).isRequired

you should pass input object to Field component with value and onChange
onChange can be your custom function:
i.e. myFunc =(val)=>{ doWhatEverWith(val)}
input={{ value: whateverState || yourValue, onChange:myFunc* }} *or this.myFunc if you defined it inside a class

@shabaz-ejaz
Copy link

shabaz-ejaz commented Oct 31, 2017

None of the above work for me. The editor gets rendered but it is not being picked up in redux form.

I can't believe there is not a single example of the actual usage of this component.

Here is what I have:

RichTextEditor component:

import React, { Component, PropTypes } from 'react';
import RichTextEditor from 'react-rte';

class RichTextMarkdown extends Component {

    static propTypes = {
        input: PropTypes.shape({
            onChange: PropTypes.func.isRequired,
            value: PropTypes.string
        }).isRequired
    };
    constructor(props) {
        super(props);
        this.state = {
            value: this.props.input.value === '' ? RichTextEditor.createEmptyValue() : RichTextEditor.createValueFromString(this.props.input.value, 'html'),
        };
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.input.value !== this.state.value.toString('html')) {
            this.setState({
                value: nextProps.input.value ?
                    RichTextEditor.createValueFromString(nextProps.input.value, 'html') :
                    RichTextEditor.createEmptyValue()
            });
        }
    }

    onChange = (value) => {
        this.setState({ value });
        console.log(value.toString('html'));

        this.props.input.onChange(value);
    };

    render() {
        return (
            <RichTextEditor value={this.state.value} onChange={this.onChange} />
        );
    }
}

export default RichTextMarkdown;

Actual usage of the component:


import RTE from '../../../elements/RichTextMarkdown ';

// ... form omitted
 <Field
        component={RTE}
        type="text"
        name="comment_closing_page"
        value="test"
        input={{ value: 'TEST', onChange: value => value.toString('html') }} />

When I submit the form I get all of my other fields but I can't get hold of the values for the text editor. Any one know why this is?

@Dem0n3D
Copy link

Dem0n3D commented Nov 11, 2017

I can't believe there is not a single example of the actual usage of this component.

Yep, I'm too.
So, I fixed it.

import React, {Component} from 'react';
import RichTextEditor from 'react-rte';

class RichTextMarkdown extends Component {

    constructor(props) {
        super(props);
        this.state = {
            value: this.props.input.value === '' ?
                RichTextEditor.createEmptyValue() :
                RichTextEditor.createValueFromString(this.props.input.value, 'html')
        };
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.input.value !== this.state.value.toString('html')) {
            this.setState({
                value: nextProps.input.value ?
                    RichTextEditor.createValueFromString(nextProps.input.value, 'html') :
                    RichTextEditor.createEmptyValue()
            });
        }
    }

    onChange(value) {
        const isTextChanged = this.state.value.toString('html') != value.toString('html');
        this.setState({value}, e => isTextChanged && this.props.input.onChange(value.toString('html')));
    };

    render() {
        return (
            <RichTextEditor value={this.state.value} onChange={this.onChange.bind(this)} />
        );
    }
}

export default RichTextMarkdown;

The problem is concurrent updates of component internal state and redux state. So, we need to put onChange dispatch in setState callback.

@Dem0n3D
Copy link

Dem0n3D commented Nov 11, 2017

And you shouldn't specify input prop of Field, redux does it by itself. Use it like a simple input:

<Field name="description" component={RichTextMarkdown} />

@Hiroki111
Copy link

@smeijer
A bit old posting, but could you explain why you put const wasSubmitting?

In my case, putting the following part into OP's code solved the initialization issue with asynchronous API calls.

componentWillReceiveProps(nextProps) {
    const isPristine = nextProps.meta.pristine; 

    if (nextProps.input.value && isPristine) {
      this.setState({
        value: this.RichTextEditor.createValueFromString(nextProps.input.value, 'markdown')
      });
    }
  }

@riflemanIm
Copy link

@Dem0n3D
Thanks!

@probabble
Copy link

based on this thread, I changed the componentWillRecieveProps in order to support React 16

sstur/react-rte#242 (comment)

componentWillReceiveProps(nextProps) {    
    this.state.value.setContentFromString(nextProps.value, "html");
}

@DemiJiang33
Copy link

@Dem0n3D
Thank you so much!

@victorpavlenko
Copy link

@Dem0n3D
Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment