admin管理员组

文章数量:1424970

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.

本文标签: