javascript - React Material-ui DatepickerTimepicker OnChange Event callback function encapsulation - Stack Overflow

I'm fairly new to React and I'm using Material-ui as an additional UI dependency. I have some

I'm fairly new to React and I'm using Material-ui as an additional UI dependency. I have some repetition in my code that is a little tricky to remove since I think I'm restricted by a Material-ui ponent's implementation.

Here's my class that I need help with re-organizing

...other imports...
import EntryForm from './entryform';
export default class TimeSheet extends Component {

constructor(props) {
    ...
    this.state = {
        entry: {
            date: null,
            startTime: null,
            endTime: null,
        },
        list: []
    };

    // ... Class method bindings here ...
}


// ------- METHODS I WOULD LIKE TO CONSOLIDATE -----
dateChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, date: new Date(date) }
    }));
}

startChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, startTime: new Date(date) }
    }));
}

endChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, endTime: new Date(date) }
    }));
}
// ------- METHODS I WOULD LIKE TO CONSOLIDATE -----

saveTimeSheetEntry(event) {
    this.setState((prevState) => ({
        ...prevState,
        list: prevState.list.concat([{
            ...prevState.entry
        }])
    }));
}

render() {
    return (
       ...some stuff

            <EntryForm
                dateChanged={this.dateChanged}
                startChanged={this.startChanged}
                endChanged={this.endChanged}
                date={this.state.entry.date}
                startTime={this.state.entry.startTime}
                endTime={this.state.entry.endTime}
                save={this.saveEntry}
            />

        ...other stuff
    )
}
}

EDIT

./EntryForm Component

const EntryForm = (props) => (
    <Paper style={paperStyle} zDepth={1}>
        <DatePicker onChange={props.dateChanged} value={props.date} hintText="Timesheet Date" />
        <TimePicker onChange={props.startChanged} value={props.startTime} hintText="Start Time" />
        <TimePicker onChange={props.endChanged} value={props.endTime} hintText="End Time" />
        <FlatButton onClick={props.save} label="Save" backgroundColor="#18cbce" fullWidth={true} />
    </Paper>
);

As you can see, there are 3 methods that I would like to try to consolidate into a single method. dateChanged startChanged and endChanged all of these methods are plugged into material-ui's Datepicker/Timepicker onChange prop. Normally I would just do something like this

handleChange(event, date, stateItem) {
    this.setState(state => ({
        ...state,
        entry: { ...state.entry, [stateItem]: date }
    }));
}

But when I try it throws an error, probably because the Date/Time picker implementation looks like this.

<Timepicker onChange={props.startChange} ...otherProps />

see the source code for this here check out line 149.

It's okay because the app is small, and it's just a basic time sheet entry. But it would bee super unruly if I had to do this with many state objects.

Is there any solution that would prevent me from having 3 different touch points for such a similar operation?

p.s. sorry for ...spread abuse :)

I'm fairly new to React and I'm using Material-ui as an additional UI dependency. I have some repetition in my code that is a little tricky to remove since I think I'm restricted by a Material-ui ponent's implementation.

Here's my class that I need help with re-organizing

...other imports...
import EntryForm from './entryform';
export default class TimeSheet extends Component {

constructor(props) {
    ...
    this.state = {
        entry: {
            date: null,
            startTime: null,
            endTime: null,
        },
        list: []
    };

    // ... Class method bindings here ...
}


// ------- METHODS I WOULD LIKE TO CONSOLIDATE -----
dateChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, date: new Date(date) }
    }));
}

startChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, startTime: new Date(date) }
    }));
}

endChanged(event, date) {
    this.setState(prevState => ({
        ...prevState,
        entry: { ...prevState.entry, endTime: new Date(date) }
    }));
}
// ------- METHODS I WOULD LIKE TO CONSOLIDATE -----

saveTimeSheetEntry(event) {
    this.setState((prevState) => ({
        ...prevState,
        list: prevState.list.concat([{
            ...prevState.entry
        }])
    }));
}

render() {
    return (
       ...some stuff

            <EntryForm
                dateChanged={this.dateChanged}
                startChanged={this.startChanged}
                endChanged={this.endChanged}
                date={this.state.entry.date}
                startTime={this.state.entry.startTime}
                endTime={this.state.entry.endTime}
                save={this.saveEntry}
            />

        ...other stuff
    )
}
}

EDIT

./EntryForm Component

const EntryForm = (props) => (
    <Paper style={paperStyle} zDepth={1}>
        <DatePicker onChange={props.dateChanged} value={props.date} hintText="Timesheet Date" />
        <TimePicker onChange={props.startChanged} value={props.startTime} hintText="Start Time" />
        <TimePicker onChange={props.endChanged} value={props.endTime} hintText="End Time" />
        <FlatButton onClick={props.save} label="Save" backgroundColor="#18cbce" fullWidth={true} />
    </Paper>
);

As you can see, there are 3 methods that I would like to try to consolidate into a single method. dateChanged startChanged and endChanged all of these methods are plugged into material-ui's Datepicker/Timepicker onChange prop. Normally I would just do something like this

handleChange(event, date, stateItem) {
    this.setState(state => ({
        ...state,
        entry: { ...state.entry, [stateItem]: date }
    }));
}

But when I try it throws an error, probably because the Date/Time picker implementation looks like this.

<Timepicker onChange={props.startChange} ...otherProps />

see the source code for this here check out line 149.

It's okay because the app is small, and it's just a basic time sheet entry. But it would bee super unruly if I had to do this with many state objects.

Is there any solution that would prevent me from having 3 different touch points for such a similar operation?

p.s. sorry for ...spread abuse :)

Share Improve this question edited Aug 5, 2017 at 3:47 Edwinj asked Jul 30, 2017 at 21:03 EdwinjEdwinj 851 gold badge4 silver badges8 bronze badges 6
  • But when I try it throws an error ( what error ? ) – btzr Commented Jul 31, 2017 at 0:20
  • sorry for ...spread abuse : you don't need to set the full state – btzr Commented Jul 31, 2017 at 0:29
  • could you explain what / when trigger: startChanged and endChanged – btzr Commented Jul 31, 2017 at 0:42
  • also if you can add the code of ./entryform' in the post ^^ – btzr Commented Jul 31, 2017 at 1:26
  • Thanks I updated my answer, you get the error date is undefined because onChange only have one parameter value you are passing the second parameter ( undefined) ^^ – btzr Commented Aug 2, 2017 at 5:27
 |  Show 1 more ment

2 Answers 2

Reset to default 2

States updates are merged

When you call setState(), React merges the object you provide into the current state.

You don't need to update the full state, react will update independently the given object, the rest will remain intact.

See: States updates are merged

Main handler

there are 3 methods that I would like to try to consolidate into a single method

You only need category and date ( no need for event ):

     handleChange(category, date) {
        this.setState(prevState => {

            // Get previous state
            const { entry } = prevState;

            // Set state: date | startTime | endTime
            entry[category] = date; 

            //Update state
            return { entry };
        });
     }

Bind handler

To make work this and setState inside an inner ponent:

<EntryForm onChange={ this.handleChange.bind(this) } {...} />

Using the handler

Just use this.props.onChange instead of startChanged, endChanged, dateChanged:

//dateChanged
this.props.onChange('date', date);

//startChanged
this.props.onChange('startTime', date);

//endChanged
this.props.onChange('endTime', date);

Timepicker

But when I try it throws an error, probably because the Date/Time picker implementation looks like this.

the onChange callback only pass one argument value (that's the date)

function onChange(value) {
  console.log(value && value.format(format));
}

Since you only need date you can override the implementation with an anonymous function
( just wrap it inside another function ):

<Timepicker onChange={ date => { props.onChange('date', date ) } />

I'm unable to ment yet. So here goes:

I don't think you can, since you need to distinguish between the states you want to set. If you consolidate these methods you would need a switch or an if or something which in my opinion is worse then this.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745418799a4626872.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信