I'm using a react datepicker component that can be found here. The component is pretty great except for what appears to be an oversight: it does not implement willReceiveProps.
To expound, I create the datpicker as below:
<DateField
dateFormat= { dateFormat}
forceValidDate={true}
defaultValue={startDate || ''}
onChange={this.handleChange.bind(null, 'start_date')}
id="start"
>
<DatePicker
navigation={true}
locale="en"
forceValidDate={true}
highlightWeekends={true}
highlightToday={true}
weekNumbers={true}
weekStartDay={0}
/>
</DateField>
Note above that there is a prop defaultValue which I pass startDate. Now, startDate can and does change for reasons that are sometimes external to the component. That value is passed during a new render() action as per usual. According to react philosophy this shouldn't be a problem.
However, it appears to me as if the value from defaultValue is only ever read once inside DateField. It is read as this.props.defaultValue. Anyone who has ever built a component relying on props should quickly recognize this is a problem. It means that when the prop is changed the new value will not be used.
Because this is a library, I cannot simply implement willReceiveProps. Does anyone know of a good workaround to get this component to either completely reset on a render or some other strategy to deal with what seems to be a big design problem?
They follow the same standards as the <input> component. defaultValue is read only once but there is also value that can be set externally. There is no need for them to use willReceiveProps.
In short, use value instead of defaultValue.
See Uncontrolled Components in React
PS: I am looking a bit into the code and it seems there are also properties text and date apart from value. Since the code (and documentation) has been removed from github, I won't inspect what is the difference between those props.
Related
I understand the concept of the Controlled component however when I think about it deeply why do we actually need it if we are using onChange method.because everytime we make some change the value of that change will be in the state so there will be a one source of truth either way. why do we need value for making it a controlled component?
<input
name="username"
onChange={this.onChange}
value={this.state.username}
type='text'
placeholder="Full Name"
/>
Because if you don't set the value on the <input> element:
value={this.state.username}
Then when the state is updated and the component re-renders it won't display a value in the UI. Regardless of the state tracked by React, ultimately the UI needs to render as plain HTML. And you need to tell that HTML what the value for that <input> is so it displays (and can be further modified).
well, let's think about it.
if it is a controlled component, it means that you can do whatever you want from the input on the onChange function right? well, now think that you are for some reason transforming the input from the user, lets think about a function that changes numbers:
onChange(event){
const inputValue = event.target.value;
const result = '$' + inputValue + '.00';
this.setState({ value});
}
right? well, basically, this tell us how we changed our state value but how does the input know about these change and the real value we want to show? how does the input know that if the user puts something it should show something else?
12 ---> $12.00
when you control an field, you need to handle the output and the input of these field, because you need to provide everything in order to properly show the data.
if you are not doing any weird magic, maybe you don't need a controlled input.
The pattern of separating out 'what happened' from 'what this does to my app' flows directly from React's use of a declarative style of programming (in comparison to imperative - see this post if you're not familiar with the distinction).
It takes a bit of getting used to when you first encounter it but as your code increases in complexity it makes more and more sense as it keeps things de-coupled and makes it easy to reason about. Changes start as events, which update the state, which is then reflected in your app. It's a loop rather than a 2-way binding.
My team and I have been using Antd a react component library. I was asked to connect google.map's Places library to an input field so we can get an easy address drop-down list.
The problem is the Antd's input component is wrapped up under the hood. So when I click on an address from google.maps Places menu it appears in the input field for a milli sec then disappears.
I tried all the event.preventDefault(), event.stopPropoagtion(). Is there any trick to combining google.maps places returned data with a well nested react-ui component?
(too long for comment)
I have the exact same problem.
I'm using NextJS with functional component and #react-google-maps/api library.
The workaround I use: simple <input> element combined with the right CSS class to make it look like the Antd <Input>.
Like this:
<LoadScript
googleMapsApiKey={process.env.NEXT_PUBLIC_GOOGLE_MAP_API_KEY}
libraries={libraries}
>
<Autocomplete
onLoad={(autocomplete) => setAutocomplete(autocomplete)}
onPlaceChanged={onPlaceChanged}
restrictions={{ country: "fr" }}
fields={['geometry.location', 'formatted_address']}
>
<input
type="text"
placeholder="Enter your address"
className="ant-input"
/>
</Autocomplete>
</LoadScript>
This way, when clicking on an address from Places menu, its value stays in the input field.
If anyone has a better and less hacky solution, I'm looking for one!
This is a very simple matter of state management. It sounds like the google-places input field was working correctly or it wouldn't have shown up at all. If your input field is connected to let's say Reactjs then you will need to add the google-places response data to your state-management and it should stop disappearing. This happens a lot when companies use custom state-management systems.
<input value={name.firstName} onChange={e => setName({firstName : e.target.value})} />
Even if we remove the value and use this code:
<input onChange={e => setName({firstName : e.target.value})} />
The app still works. What is the difference?
Second question, Do you think the hooks will be used as default for React to use? Will context api be replacement for redux in close future?
It's better to use value attribute, because if some error is thrown while setting a value, user will see it. For example, if value stops being stored in a state, the input will stop too. If you don't use value tag, input won't stop in that case.
NO. In react docs, we read "We intend for Hooks to cover all existing use cases for classes, but we will keep supporting class components for the foreseeable future. At Facebook, we have tens of thousands of components written as classes, and we have absolutely no plans to rewrite them. Instead, we are starting to use Hooks in the new code side by side with classes."
ContextAPI won't replace redux because of few big reasons. You don't have time travel debugger or configurable middleware.
Also you can read this article
Is there a way to pass classname to matererial-ui datepicker's dialog.
http://www.material-ui.com/#/components/date-picker
Material-ui's datepicker accepts classname as a prop. But, this gets applied to the text-field upon which we want to trigger the date-dialog.
I want to pass a class attribute to the date-popup itself. Something like:
dialogClassName
The need is I want to access if the click was done somewhere inside the date-dialog and manage some other part of my code based on that. I can't figure out how to make the date-dialog accept a classname.
This issue was a bit boosting,https://github.com/mui-org/material-ui/issues/5329 but passing a dialogClassName doesn't get applied.
There is a solution which I came across by going through the DatePicker Code. You can pass the following props to the DatePicker
<DatePicker>
PopperProps={{
className: classes.desktopView,
}}
DialogProps={{
className: classes.mobileView,
}}
</DatePicker>
I'm afraid you cannot do that without modifying the DatePicket component ( at least not without some wild hacks).
If you really need this functionality you can fork material-ui repository, make the changes and submit a pull request. Or, in you project, create a local DatePicker component and do the changes there, but this approach requires you to update your version in case material-ui's version is updated.
There is no solution as of yet. However there is a workaround to pass a css class name to popup/dialog container.
Pass an img tag for rightArrowIcon props of datepicker with onload function to call its parent and inject css class.
<DatePicker
disableToolbar={true}
variant="inline"
inputVariant="outlined"
rightArrowIcon={<img src="/images/chevron-right_1.svg" id="datepicker-arrow-right" onLoad={injectTheme}/>}
leftArrowIcon={<img src="/images/chevron-right_1.svg" style={{transform:"rotate(180deg)"}}/>}
....
....
....
/>
const injectTheme=()=>{
let node = document.getElementById("datepicker-arrow-right").parentNode.parentNode.parentNode.parentNode.parentNode.parentElement;
node.classList.add("Css-Class-Name");
}
Some material-ui components have errorText as a prop which we can use to show errors, But, doing that in react become lot complex if my form has large number of field components.
Please suggest the best way to handle client-side validation with material-ui comonents.
I think your issue is that you have to manage a lot with state/store. In react validation is complex because of one-way binding.
This library https://github.com/vishalvisd/react-validator is one which I found that supports material-ui component validation. Though in general you may use this to validate any component.
I would suggest using some HoC (Higher-order Component) approach. I tested many solutions for form validation in React JS, the one that I always choose is: react-validation-mixin. Take a look at this example.
Example of the standard input:
<input
type='text'
placeholder='Username'
value={this.props.username}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
/>
In this example value of that input comes from props (example with Flux implementation) and that's probably what you aim for too (lots of inputs).
onChange will need to handle value change so that this.props.username gets updated too and onBlur will trigger validation check (so that the error will show up once user leaves the input).
In order to get the error message, use: this.props.getValidationMessages('username')
It's a universal solution and you can use it in different libs. But taking TextField from material-ui, as you asked:
<TextField
floatingLabelText="Username"
value={this.props.username}
errorText={this.props.getValidationMessages('username')}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
...
/>
Remember to use HoC with your component: export default validation(strategy)(UserLogin) That way, you will get all the necessary helper methods in props.
If you are using Redux in React project, redux-form give you a simple way to implement form validation.
Check this out: http://redux-form.com/6.4.3/examples/syncValidation/