Feature/normalizr/add country entity and students that belongs to contry#36
Conversation
| this.gotActiveTraining = false; | ||
| this.fullname = ""; | ||
| this.email = ""; | ||
| this.countryId = -1; |
There was a problem hiding this comment.
-1 smells bad to me. Why not null or undefined?
There was a problem hiding this comment.
I think null can be a good value, on the other hand is it a good idea to define this as a class or should it be an interface? Should we add a factory to initialize a new instance?
There was a problem hiding this comment.
I think we are using this value because Uncontrolled input warning (If you initialize input value to null, it means that is uncontrolled component) But I think that this initialization has to be component liability and it doesn't delegate to class constructor used in reducer default value state. What do you think?
There was a problem hiding this comment.
Yep, if it's a component problem, let the component to deal with it.
On the other hand, I would use an interface too. I avoid factory methods unless you need to share some initialization logic that I don't see on this case.
| return { | ||
| id: country.id, | ||
| name: country.name | ||
| } |
There was a problem hiding this comment.
Does this need a new object? Is not just an interface? In TS, any Country is a CountryView because of structural typing, so just use the original object, even when it has extra props, no?
There was a problem hiding this comment.
You are right, we can return original object and in the future, map additional props or some format
| gotActiveTraining: student.gotActiveTraining, | ||
| fullname: student.fullname, | ||
| email: student.email | ||
| email: student.email, |
There was a problem hiding this comment.
Make trailing comma a convention to avoid this in PRs. It can be set up in TSLint.
| email: student.email, | ||
| country: { | ||
| id: student.countryId, | ||
| name: '' |
There was a problem hiding this comment.
This seems wrong (before looking more code).
| this.gotActiveTraining = false; | ||
| this.fullname = ""; | ||
| this.email = ""; | ||
| this.country = new CountryView(); |
There was a problem hiding this comment.
This also seems wrong. Either leave country undefined, or use a CountryView.Empty like with the Null Object pattern. Otherwise it seems you're creating a brand new country for each student.
There was a problem hiding this comment.
Agree, or we could assign a default country entry. Thinking now about pros adding a factory to create then StudentView
| export const getCountries = (state) : CountryView[] => { | ||
| const ids = getIds(state.countryDomain.allIds); | ||
| return ids.map(id => getCountry(state, id)); | ||
| } |
There was a problem hiding this comment.
Why getCountry and getCountries are on different places?
| return state; | ||
| } | ||
|
|
||
| export const getIds = (state: number[]) => state; |
| export const getStudent = (state, id) : StudentView => { | ||
| return { | ||
| ...state.studentDomain.byId[id], | ||
| country: getCountry(state, state.studentDomain.byId[id].country) |
There was a problem hiding this comment.
I got lost: previously state was the dictionary of students. Now it's the global state. This seems hard to manage unless you strong-type arguments to prevent mismatches.
| @@ -0,0 +1,4 @@ | |||
| import { schema } from 'normalizr'; | |||
|
|
|||
| export const countrySchema = new schema.Entity('countries'); | |||
There was a problem hiding this comment.
I think we should put all schemas on the same file, so you can export without the schema prefix, like mySchema.country.
There was a problem hiding this comment.
Just in case it scales we could go for a solution like
+ src
+ schema
* index.ts
* country.ts
* student.ts
Then just in index we export all the schemas.
If somebody has to use this he only has to worry about
import "./schema"
But on the name of the schema it self, not sure if we should keep the "Schema" prefix, to avoid creating aliases if there are name collisions.
There was a problem hiding this comment.
Yep, the index would be a solution in case we need to break down. Btw I meant suffix, not prefix.
| import { countrySchema } from './countrySchema'; | ||
|
|
||
| export const studentSchema = new schema.Entity('students', { | ||
| country: countrySchema |
There was a problem hiding this comment.
This is not true. Current API returns countryId, not a nested object. What I have understood so far is that this line would be helpful to denormalize country information from students, but this is not going to happen. If student gets a country object just for the UI, it doesn't apply here, and probably we would like to stop adding that country to the student object, instead you can look up the country from the Id when needed. Thumbs down to normalizr here, to extract nested object, I see value on it to convert countries array to a dictionary.
| allIds | ||
| }); | ||
|
|
||
| export const getCountries = (state) : CountryView[] => { |
There was a problem hiding this comment.
getCountries(state)
This state should be already countryDomain
| @@ -6,5 +6,6 @@ export const actionsEnums = { | |||
| STUDENT_FIELD_VALUE_CHANGED: "STUDENT_FIELD_VALUE_CHANGED", | |||
There was a problem hiding this comment.
I think we can remove this action is covered by a thunk function
| <div className={wrapperClass}> | ||
| <label htmlFor={this.props.name}> | ||
| {this.props.label} | ||
| </label> |
There was a problem hiding this comment.
This label should not be included in this component
No description provided.