Warm tip: This article is reproduced from stackoverflow.com, please click
javascript reactjs

Own time picker does not take the default value

发布于 2020-03-27 10:21:50

I created two inputs. In one I choose hours, in the second minute. When I click edit, the hour and minute should be displayed in the input, converted to 600 seconds per hour and minutes. The time you want to edit should be displayed in the injection. I do not want to change anything. Gives you save. The hour remains unchanged.

Code here: https://stackblitz.com/edit/react-uadnrj

Picture: https://imgur.com/zF18gXh

class EditForm extends React.Component {
  render() {
    return (
      <div className="asd">
        Hours:
        <input type="number" defaultValue={this.props.displayH}onChange={(e) => this.props.handleHours(e)} value={this.props.displayH} />
        Minutes: 
         <input type="number"  defaultValue={this.props.displayH} onChange={(e) => this.props.handleMinutes(e)} value={this.props.displayM} />
        <button onClick={this.props.onSave} type="submit">Save</button>
        <button onClick={this.props.onCancel} type="submit">Cancel</button>
      </div>
    )
  }
}


class Todo extends Component {

  state = {
    isEditing: false,
    displayH: '',
    displayM: '',
    hours: '',
    minutes: '',
    seconds: ''
  }



  displayHours = (item) => {
    let d = Number(item);
    let hours = Math.floor(d / 3600);

    return hours; 
  }

  displayMinutes = (item) => {
    let d = Number(item);
    let minutes = Math.floor(d % 3600 / 60);

    return minutes; 
  }


  setEditing = () => {
    this.setState({
      isEditing: !this.state.isEditing
    })
  }

  handleHours = (hours) => {
    this.setState({
      displayH: this.displayHours(hours),
      hours: hours * 60 * 60
    })
    console.log('changed', hours);
  }

  handleMinutes = (minutes) => {
    this.setState({
      displayM:  this.displayMinutes(minutes),
      minutes: minutes * 60
    })
    console.log('changed', minutes);
  }


  onSave = () => {

    const { description } = this.state;

    this.props.update(this.props.index, { seconds});

    this.setState({
      isEditing: false
    })
  }

  onCancel = () => {
    this.setState({
      isEditing: false,
    });
  }

  componentDidMount = () => {
    const { todo } = this.props;

    this.setState({
      seconds: todo.seconds
    })
  }

  render() {

    return (
      <div>
        {this.state.isEditing

          ? (<EditForm
            handleHours={this.handleHours}
            handleMinutes={this.handleMinutes}
            onSave={this.onSave}
            onCancel={this.onCancel}
            displayH = {this.state.displayH}
            displayM = {this.state.displayM}
          />)
          : (
            <li>
              <h1>{this.state.displayH}  {this.state.displayM}</h1>
              <button onClick={() => this.setEditing()}>Edit</button>
            </li>
          )

        }
      </div>
    )
  }
}
Questioner
Umbro
Viewed
134
Michael Cox 2019-07-03 23:24

You're missing the class constructor. You need it at the beginning of your class components when you set the state or pull in props. You have it in App, but you're missing it in Todo. For example Todos would be like this:

class Todo extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isEditing: false,
      displayH: '',
      displayM: '',
      hours: '',
      minutes: '',
      seconds: ''
    };
  }

  //...the rest of your code
}

For components that don't have any state variables you could simplify them by converting them to functional components:

const CustomInput = props => (
  <div className="wrapper">
    <i onClick={props.onClick} aria-hidden="true" className="fa fa-calendar"></i>
    <input onClick={props.onClick} className="dateInput" value={props.value} type="text" />
  </div>
);

Also, keep in mind that inputs' onChange returns an event, not the value. So, you're handle functions need to parse the event:

  handleMinutes = ({ target: { value: minutes }}) => {
    this.setState({
      displayM:  this.displayMinutes(minutes),
      minutes: minutes * 60
    })
    console.log('changed', minutes);
  }

I had to rework a lot of the components, but I got it working. Here's the code:

import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";

class EditForm extends Component {
  constructor(props) {
    super(props);
    console.log(props);

    this.state = {
      hours: props.displayH,
      minutes: props.displayM,
    };
  }

  handleHours = ({ target: { value: hours }}) => {
    this.setState({
      hours,
    });
  }

  handleMinutes = ({ target: { value: minutes }}) => {
    this.setState({
      minutes,
    })
    console.log('changed', minutes);
  }

  render() {
    const { hours, minutes } = this.state;
    return (
      <div className="asd">
        Hours:
        <input type="number" value={hours} onChange={this.handleHours} />
        Minutes: 
          <input type="number"  value={minutes} onChange={this.handleMinutes} />
        <button onClick={() => this.props.onSave(hours, minutes)} type="submit">Save</button>
        <button onClick={this.props.onCancel} type="submit">Cancel</button>
      </div>
    )
  }
}

class Todo extends Component {
  constructor(props) {
    super(props);
    console.log(props);

    const { seconds } = props.todo;

    const displayH = Math.floor(Number(seconds) / 3600) ?
      Math.floor(Number(seconds) / 3600) :
      '';

    const displayM = Math.floor(Number(seconds) % 3600 / 60) ?
      Math.floor(Number(seconds) % 3600 / 60) :
      '';

    this.state = {
      isEditing: false,
      displayH,
      displayM,
    };
  }

  componentDidUpdate(prevProps) {
    const { seconds } = this.props.todo;
    const { seconds: prevSeconds } = prevProps.todo;
    // Typical usage (don't forget to compare props):
    if (seconds !== prevSeconds) {
      const displayH = Math.floor(Number(seconds) / 3600) ?
        Math.floor(Number(seconds) / 3600) :
        '';

      const displayM = Math.floor(Number(seconds) % 3600 / 60) ?
        Math.floor(Number(seconds) % 3600 / 60) :
        '';
      this.setState({
        displayH,
        displayM,
      });
    }
  }

  setEditing = () => {
    this.setState({
      isEditing: !this.state.isEditing
    });
  }

  onSave = (hours, minutes) => {
    console.log('saving', hours, minutes);

    const seconds = (hours * 60 * 60) + (minutes * 60);

    this.props.update(this.props.index, { seconds });

    this.setState({
      isEditing: false
    })
  }

  onCancel = () => {
    this.setState({
      isEditing: false,
    });
  }

  componentDidMount = () => {
    const { todo: { seconds } } = this.props;

    this.setState({
      seconds
    })
  }

  render() {
    const { displayH, displayM } = this.state;
    console.log('rendering Todo');

    return (
      <div>
        {this.state.isEditing

          ? (
            <EditForm
              handleHours={this.handleHours}
              handleMinutes={this.handleMinutes}
              onSave={this.onSave}
              onCancel={this.onCancel}
              displayH = {displayH}
              displayM = {displayM}
            />
          )
          : (
            <li>
              <h1>
                { displayH && `${displayH}h` }
                { displayM && `${displayM}m` }</h1>
              <button onClick={() => this.setEditing()}>Edit</button>
            </li>
          )

        }
      </div>
    )
  }
}

class App extends React.Component {
  constructor() {
    this.state = {
      todos: [
        {
          seconds: 600
        }
      ]
    };
  }

  update = (index, todo) => {
    console.log('updating', todo, index);
    this.setState({
      todos: [
        ...this.state.todos.slice(0, index),
        Object.assign({}, this.state.todos[index], todo),
        ...this.state.todos.slice(index + 1)]
    })
  }

  render() {
    console.log('rendering App');
    return (
      <div>
        <ul>
          {
            this.state.todos
              .map((todo, index) =>
                <Todo
                  key={index}
                  index={index}
                  todo={todo}
                  update={this.update}
                />
              )
          }
        </ul>
      </div>
    );
  }
}
render(<App />, document.getElementById('root'));