Closed iwilsonq closed 6 years ago
handleRecordSubmit = () => {
const { category, title, startTime, duration, onRecordSubmit } = this.state;
const id = uuid();
onRecordSubmit({ category, title, startTime, duration, id });
};
@iwilsonq But onRecordSubmit is a function, a prop from a parent component. Do you mean to suggest adding onRecordSubmit in state of this component? and just use variable?
Oh I see my error, I meant to take onRecordSubmit from props! I intended to say that there are places where es6 destructuring can make it cleaner and easier to read 😅 . Compare that snippet to this one
handleRecordSubmit = () => {
const category = this.state.category;
const task = this.state.task;
const startTime = this.state.startTime;
const duration = this.state.duration;
const id = uuid();
this.props.onRecordSubmit({ category, task, startTime, duration, id });
};
because jsx component has be inside a enclosing tag, so I am adding
as wrapperclass CategoryColorGroup extends Component {
render() {
const ID = this.props.id;
const category = this.props.data.category;
const color = this.props.data.color;
return (
<div className="category-color-form">
<input
id={ID}
name="color"
type="color"
value={color}
className="input-color"
onChange={this.props.onInputChange}
/>
<input
id={ID}
name="category"
value={category}
className="input-category"
placeholder="new category"
onChange={this.props.onInputChange}
autoComplete="off"
/>
</div>
);
}
}
Then, though I have only one form and also onSubmit fn() attached, when I press enter on CategoryColorGroup
, function does not get invoked. Is it because I have div as wrapper?
render() {
return (
<div className="setting">
<hr />
<p className="setting-title">Category Setting</p>
<form onSubmit={this.onSaveClick}>
{this.state.categories.map((category, i) => (
<CategoryColorGroup
key={i}
id={i}
data={category}
onInputChange={this.onInputChange}
/>
))}
</form>
<button className="button-modal-save" onClick={this.onSaveClick}>
Save
</button>
<button className="button-modal-cancel" onClick={this.onCancelClick}>
Cancel
</button>
</div>
);
}
}
@iwilsonq also, did you mean to say to destruct ones that are not functions as such below?
handleRecordSubmit = () => {
const { category, task, startTime, duration, onRecordSubmit} = this.state;
const color = generateRandomColor(category, this.props.categories);
const id = generateID();
this.props.onRecordSubmit({ category, task, startTime, duration, color, id });
};
Yes like that basically, or this
handleRecordSubmit = () => {
const { category, task, startTime, duration} = this.state;
const color = generateRandomColor(category, this.props.categories);
const id = generateID();
this.props.onRecordSubmit({ category, task, startTime, duration, color, id });
};
As for the form, it should work I think, can you use console.log and see if this.onSave
is being called?
if you refer to this.onSaveClick
it does not get invoked.
Well looking back, the categories probably dont need to be rendered from state, you should try to keep the state
of your component as light as possible. There are two ways to do this here:
Controlled component form input. You'll use component state in CategorySettings to store the currently entered values of the inputs. When onSubmit
is called from the form, the onSave
function takes those values out of state and submits them.
Regular HTML form. You'll just have a bunch of tags under your form, when you hit submit, your form will have a reference to those inputs. This is more fragile/static since it doesnt rely on component state.
Basically, use state to hold the values you care about. Don't use state to render input fields at all, unless its like a showField
boolean.
If I understood correctly, the first option is basically what the current codes are doing. onInputChange
controls the input as it changes and stored them as state. then OnSaveClick, it submits category data inside state.
also still not understanding why it does not log out anything.
onSaveClick = () => {
console.log('hello world')
const data = this.state.categories;
this.props.onSave(data);
this.props.closeModal();
};
onCancelClick = () => {
this.props.closeModal();
};
render() {
return (
<div className="setting">
<hr />
<p className="setting-title">Category Setting</p>
<form onSubmit={this.onSaveClick}>
{this.state.categories.map((category, i) => (
<CategoryColorGroup
key={i}
id={i}
data={category}
onInputChange={this.onInputChange}
/>
))}
</form>
<button className="button-modal-save" onClick={this.onSaveClick}>
Save
</button>
<button className="button-modal-cancel" onClick={this.onCancelClick}>
Cancel
</button>
</div>
);
}
}
One more thing! Most of the things I'd improve are things that your linter actually pick up, just be sure to get eslint working with your IDE 👍
For example, using destructuring in Timers.jsx:
Regarding the assignment of
const id = uuid()
here, this operation is usually done on the backend, sometimes even by the database you're using. In the spirit of keeping backend concerns separate from the client, I'd move this to your apiLocalStorage service that 'mocks' the backend, namely to thesaveRecords
method.For now, saving the whole list of records works with smaller data, but I'd recommend creating a
saveOne
orinsertOne
method on the 'backend' service and just call that method multiple times. This'll make it easier to compose API calls on the backend; remember that each record might have dozens of fields, it would be quite a lot of work to save multiple records at a time. On top of that there might be a pipeline of 6 methods or hooks that need to be called on the backend for eachinsertOne
call in order to keep the integrity all of the other data in order.That tangent aside, I think for the scope of this project, you've implemented it pretty well 😄
Inside CategorySetting.jsx there are some concerns with naming. The
Field
component should be calledCategoryColorForm
or evenCategoryColorGroup
. For thefields
field inCategorySetting
state, I think thatfields
should be calledcategories
andcategory
should be renamed toname
, since it feels like from an outsiders perspective thatfields
is pretty broad and can be interpreted for many different parts of this app.To summarize that, ive updated the code of
CategorySetting
's render methodBy wrapping all of the category color groups in a form and giving that form an
onSubmit
prop, the user can submit it by pressingenter
. They can also click the save button as it stands. The big thing to note is that there is only one form component and n inputs, one for each category. I think this makes sense with the current setup, I wouldn't expect n forms within the same modal after all.I'll stop for now, comment if you have any questions 🔨