React-Select how to handle default value without overriding selected value? - reactjs

I have a form that I want to prefill with values if exists, but when I use it like below with React-Select it won't select the options on select
value={rowData?.components ? getOptions(rowData.components, components, 'name') : []}
Obviously, this is the problematic part : [].
I've also tried : null but it doesn't help.
When I tried this it just didn't render the default values:
rowData?.components && getOptions(rowData.components, components, 'name')
How can I work around this?

Eventually I've used defaultValue instead:
defaultValue={rowData?.components ? getOptions(rowData.components, components, 'name') : []}
so it doesn't override the default field, but still provides what I needed. for some reason it didn't work before, but after I've updated React-Select it worked fine.

class Selector extends Component {
constructor(){
super(props);
this.state={
selectedValue:''
}
}
componentDidMount(){
/*
fetch the value and assign to state
*/
this.setState({selectedValue:fetchedValue})
}
render(
return(
<ReactSelect value={this.state.selectedValue} onChange={()=>this.setState({selectedValue:option})} />
)
)
}
The problem happening is you are fixing the value if already present and that value is not updating so a better option can be to store the value in a state and then onChange change the value of the checkbox.

Related

MultiSelect does not update value when value state changes (PrimeReact UI)

https://www.primefaces.org/primereact/showcase/#/datatable
https://www.primefaces.org/primereact/showcase/#/multiselect
I am using the PrimeReact library to create and customize a Data Table.
My table is dynamic and will build itself based on the data given to it. I am assigning different filters to each column depending on the column's data type, but because there are a variable number of columns I must create the filters dynamically.
To accomplish this I am factoring out the filter logic into a separate class which contain their state and logic.
My issue is that the MultiSelect component I am using as a filter interface does not update its value when it's value's state is updated. After updating the state the value remains null. As the MultiSelect component does not have a reference to the previously selected values I can only choose one value at a time.
I think I am missing some understanding regarding class components, as I usually use functional components. I used a class component in this case so that I could access filterElement from the instantiated DropDownFilter class through DropDownFilter.filterElement() and use as a prop in the Column component.
import React from 'react'
import { MultiSelect } from 'primereact/multiselect';
class DropDownFilter extends React.Component {
constructor(props) {
super(props);
this.multiSelRef = React.createRef();
this.state = {
selectedOptions: [],
}
// Added following two lines trying to fix issue but they did not alter behaviour
this.onOptionsChange = this.onOptionsChange.bind(this)
this.filterElement = this.filterElement.bind(this)
}
onOptionsChange = (e) => {
this.props.dt.current.filter(e.value, this.props.field, 'in');
this.setState({selectedOptions : e.value})
}
filterElement = () => {
return (
<React.Fragment>
<MultiSelect
ref={this.multiSelRef}
value={this.state.selectedOptions} //*** value is null even when selectedOptions has been updated after user chooses option.
// Confirmed by viewing value through multiSelRef
options={this.props.options}
onChange={this.onOptionsChange}
optionLabel="option"
optionValue="option"
className="p-column-filter"
/>
</React.Fragment>
)
}
}
export default DropDownFilter;
I learned the state was not working in this case because I was instantiating the DropDownFilter using the new keyword in when using it. This means it wasnt being mounted to the DOM and could not use state.
I am still having issues regarding implementing the custom columns with filters, but I have posted a new question to handle that scope with my new findings.

React can not access variable from return

I am very new to React and I can not solve this issue for a very long time. The idea is the following, I get some user info from database and pass it into cookies. From react side I get this cookies as JSON object and I need to render menu for user depending on values in this object. Right now I pass this object that I get from cookies from parent Component and I try to access it from Settings component. The issue is that I can see access this object from test function, however when I try to access this data from return it gives me undefined error. The function that returns value from cookies is sync, I have no idea why that might happen, please help.....
Since this.state.shopSettings["new_orders"] is boolean, use ternary.
Don't copy props to the state inside constructor as the constructor is executed only once. So updates to the props won't be reflected in the component.
Like this
<button onClick={this.test}>
{props.shopSettings && (props.shopSettings["new_orders"] ? 'true button' : 'false button')}
</button>
It solves very easily with this code, now I can access any key from shopSettings inside return without any issues
class Index extends React.Component {
state = {
shopSettings: Cookies.getJSON('shopSettings')
}
render() {
const {shopSettings} = this.state
if (!shopSettings) {
return null
}
return (
<div>Hello</div>
)
}

How to store the information in react component.

When I am asking this question, lots of doubts are coming into my mind. well, first I will give my problem description.
I have component X. and it contains checkboxes and a search box.
while something typed (call it search_query) in search box,
X needed to update the checkboxes which matches the search_query. [note that I got all the values of checkboxes by some api call. and it is done when component created. ]
First doubts I came to my mind is that
store (search_query) and (values of checkboxes) in component state
if the values are more searching takes more time.
is it possible to change the values of props inside the component
or is there any other way to do it ??
Since no code is shared. Assuming you are using plain React ( no Redux, middlewares are used ).
Answering your question:
[1] Is it possible to change the values of props inside the component?
Changing props values inside the component is a bad approach.
"All React components must act like pure functions with respect to their props."
[ref: https://facebook.github.io/react/docs/components-and-props.html#props-are-read-only]
Also, the view doesn't get the update if props values changed within the component.
[2] or is there any other way to do it.
yes ( without mutation inside the component )
using "state" property to hold values & setState to update values.
[3] How to store the information in react component?
Let's rename component X as FilterData,
searchbox ( SearchBox ) & checkboxes (SelectionBox) are two individual components.
// Define state to FilterData
class FilterData extends React.Component {
constructor() {
super()
this.state = {
term: '',
searchResults: []
}
}
....
}
// pass the state values to child components as props
class FilterData extends React.Component {
....
render() {
return (
<div>
<SearchBox term={this.state.term} />
<SelectionBox options={this.state.searchResults} />
</div>
)
}
}
In React App,
data flows top down (unidirectional) and there should be a single source of truth.
SearchBox & SelectionBox are two individual (sibling) components,
SearchBox's state has terms ( which has the search string )
When the user enters input SearchBox will update its state and possible to detect change event and fire ajax and get the response.
How SelectionBox can detect search that had happened, how it can get data.
This is why the state is moved to common ancestor FilterData.
[Ref: https://facebook.github.io/react/docs/lifting-state-up.html]
[Ref: https://facebook.github.io/react/docs/state-and-lifecycle.html#the-data-flows-down]
Code Sample -----------------------------------------------------
Selected values are not saved:
https://codepen.io/sudhnk/pen/NgWgqe?editors=1010
Selected values are saved:
https://codepen.io/sudhnk/pen/JJjyZw?editors=1010

Checkbox not changing check attribute after state was changed

Here is a some parts of code I am using:
class FileItem extends Component {
constructor(props) {
super(props);
// Initial state
this.state = {
hover: false,
checked: false
};
this.pickFile = this.pickFile.bind(this);
}
pickFile(e){
e.stopPropagation();
this.state.checked ? this.props.removeSelectedPaths(this.props.path) : this.props.addSelectedPaths(this.props.path);
}
//set the checked status for the checkboxes if file\folder are picked
componentWillReceiveProps(nextProps){
this.setState({checked: nextProps.selectedPaths.indexOf(this.props.path) != -1 });
}
render(){
return(
<div className='select-mode'><input id='files-select' type='checkbox' checked={this.state.checked} onClick={this.pickFile}/></div>
)
}
How this should work:
When you pick a file it should set the checked status of its checkbox. And when you use slect all files checkbox( it is not in code here) it pushes all paths to the redux state in the selectedPAths array and all files should have checked checkboxes as they are selected.
Components structure:
Files - container conencted to the redux state. Send props to FileList
FileList - dumb component wrapper for each FileItem. Sending props to FileItem.
FileItem - component which renders row for specific file
The problem:
The problem is when I use Select All files functionality the checkbox for individual file not updating the UI to show the check mark on checkbox. While picking file by file is working fine and checkbox changes to checked(but same logic is used to see if it should be checked).
Weird facts:
When I do
console.log(this.state.checked) in render it shows me that state is
true. So it should change checkbox to checked but not.
I have a similar logic for the Select All files checkbox ( it uses componentWillReceiveProps method to check if all files was selected and change the checked status) and it is working just fine.
You can reveal that the checkbox checked after you picked all files just hovering it over(which triggers on mouse enter event and changes the state which leads to re rendering). I have a feeling like a render is getting lost after state changed but the weird fact 1 tells opposite thing as we have true in state but not checked checkbox in UI.
Sometimes the component needs a key, usually when using lists. this is useful for detecting changes. Try this:
<FileItem key={file.index.toString() + file.isChecked} path={filepath} checked={file.isChecked} />
We say to react that there was a change. To re-render.
Suggest:
You must pass the checked parameter from the parent if you want to handle the status of all the items
files.map (file =>
<fileItem key={file.key} path={filepath} checked={AllChecked} />
and at FileItem:
class FileItem extends Component {
constructor(props) {
super(props);
// Initial state
this.state = {
hover: false,
checked: props.checked// <= here
};
this.pickFile = this.pickFile.bind(this);
}

ReactJS fields are not editable for Dynamic Fields

I have a requirement wherein I need to create fields dynamically through JSON.
I have created my components as required and the page is rendered with required fields.
But the fields are in non editable state, even though I had a onchange function in InputField js file. Following is the part of the code from my component
onChange(event) {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
return (
this.props.screenField.fieldType === 'INPUT'
? <div className='form-group'>
<label htmlFor={this.props.screenField.name}>{this.props.screenField.label}:</label>
<input type={this.props.screenField.dataType === 'BOOLEAN'
? 'checkbox'
: this.props.screenField.dataType}
name={this.props.screenField.name}
id={this.props.screenField.name}
placeholder={this.props.screenField.helpText}
required={this.props.screenField.isRequired}
value={this.props.screenField.value} className='form-control'
onChange={this.onChange.bind(this)}/>
</div>
: null
)
}
Please find the URL below of the entire code.
https://github.com/yvsivateja/ReactJSApplications/tree/one/React-json-render
The React philosophy is that props should be immutable and to use the state if you need to change something.
Bind the value to the state not props. In the constructor set the initial state:
constructor(props) {
super(props);
this.state = {[this.props.screenField.name] : this.props.screenField.value};
}
bind to the state:
value={this.state[this.props.screenField.name]} className='form-control'
You might want to move all the logic out of the render function as that is usually good practice. The render function should only contain the components defined in a declarative way, just like HTML.
One thing you seem to be missing is the braces that are used to evaluate an expression inside JSX. Whatever you have in the return statement right now should be enclosed in {}:
{this.props.... === 'INPUT' ? ... : ...}
As I mentioned before, think about moving that outside render. Maybe you could use an if statement before the return. Another option is extracting the div into its own component (or just return it from a helper function).

Resources