Wolfyaskingstuff
Wolfyaskingstuff

Reputation: 139

react props undefined inside the constructor and exist inside the render

I'm trying to create a controlled text area.

class TextArea extends React.Component {
  constructor(props) {
    super(props);
    this.state= {
        text: this.props.initial
    };
    this.handleChange = this.handleChange.bind(this);
  }

handleChange(event) {
    //some handle
}

render() {
    return (
        <textarea
          value={this.state.text}
          placeholder={this.props.initial}
          onChange={this.handleChange}
        />
    );
  }
}

For some reason if I console.log the this.props.initial in the constructor I get an undefined.

But the placeholder works.

What I would like to do is to ditch the placeholder and set an initial value to that the user can edit and copy and interact with. (basically normal text and not a placeholder, but I cannot do that because it doesn't work)

What am I doing wrong?

Edit: The way that I am passing props.initial to the textarea:

<TextArea
  initial={this.state.json.initial}
  text={this.state.json.text}
  changeHandler={this.handleChange}
/>

I am getting the json from a $.getJSON call and I think that the textarea gets rendered before the json call is finished. Is there any way to run the render function only after the componentWillMount function?

Upvotes: 5

Views: 3610

Answers (3)

Maru
Maru

Reputation: 600

the important part to understand is that the constructor already takes in the props as parameters so you can access props directly in the constructor as props. no need to access it via this.props as long as you are inside the constructor

constructor(props) {
  super(props);
  this.state= {
    text: props.initial
  }
}

the code above should work


However, this is a better way of structuring a component like TextArea and it should also solve your problem of props.initial not having a value on runtime

First, you need to prepare the handleChange method in the parent component

class ParentComponent extends Component {
  constructor(props) {
    super(props)
    this.state = {
      myTextArea: ''
    }

    this.handleChange = this.handleChange.bind(this)
  }

  handleChange (e) {
    this.setState({myTextArea: e.target.value})
  }

  render () {
    return (
      <TextArea
        value={myTextArea}
        onChange={this.handleChange}
      />
    )
  }
}

and on the text area component, you refer to onchange method passed through the props when defining the onchange method of your textarea.

<textarea
  value={this.props.value}
  placeholder="Something"
  onChange={this.props.handleChange}
/>

the benefit of this approach is that one, the one that calls the textarea will always have an updated value, and two, this child element doesnt need to have a state. it makes managing a large react app easier and its the correct mind set to have once you start trying to implement Redux or similar frameworks to handle your state for you

Upvotes: 0

Alessander Franca
Alessander Franca

Reputation: 2753

You have to garantee that this.props.inital exists:

{ this.state.json && this.state.json.initial &&
  <TextArea initial={this.state.json.initial} text={this.state.json.text} changeHandler={this.handleChange}/>
}

Upvotes: 0

Hemerson Carlin
Hemerson Carlin

Reputation: 7424

Remove this from this.props in the constructor since you have access to props from its argument list.

class TextArea extends React.Component {
  constructor(props){
    super(props)
    
    this.state = {
      text: props.initial,
    }
    
    this.handleChange = this.handleChange.bind(this)
  }
  
  handleChange(event){
    this.setState({ text: event.target.value })
  }
  
  render(){
    return (
      <div>
        <div>Initial text: {this.props.initial}</div>
        <textarea
          value={this.state.text}
          placeholder={this.props.initial}
          onChange={this.handleChange}
        />
      </div>
    )
  }
}

ReactDOM.render(
  <TextArea />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>


<div id="root"></div>

Upvotes: 2

Related Questions