Not able to access array passed as props from parent - React - javascript

Getting started with React. I have two drop-downs in the child component WeatherOptionsView. I'm trying to set it's default value based on the prop array of previously selected values passed from Parent component WeatherContainerView. I also want to set it to the state as the value will change onChange of dropdown going forward.
The UI blows up when I do this. When I print the values of props, I see that the selectedCodes is null. Where am I going wrong with this? Any help will be appreciated. Thanks!
console.log(this.props.isFailed); //false
console.log(this.props.selectedValues); //null
WeatherOptionsContainer.js
class WeatherOptionsContainer extends React.Component {
constructor(props) {
super(props);
this.state = { isFailed: true, isLoading: false, selectedValues: ['City1', 'City2']};
}
render() {
return (
<WeatherOptionsView
isFailed={this.state.isFailed}
isLoading={this.state.isLoading}
selectedValues={this.state.selectedValues}
/>
);
}
}
WeatherOptionsView.js
class WeatherOptionsView extends React.Component {
constructor(props) {
super(props);
this.state = { reasonState: false, selectedValues: this.props.selectedValues };
}
render() {
const cx = classNames.bind(styles);
return (
<ContentContainer fill>
<Spacer marginTop="none" marginBottom="large+1" marginLeft="none" marginRight="none" paddingTop="large+2" paddingBottom="none" paddingLeft="large+2" paddingRight="large+2">
<Fieldset legend="City">
<Grid>
<Grid.Row>
<Grid.Column tiny={3}>
<SelectField selectId="State1" required placeholder="Select" label={["City:"]} error={["Error message"]} isInvalid={this.state.reasonState} defaultValue={this.props.selectedValues[0]}>
<Select.Option value="City1" display="City1" />
<Select.Option value="City2" display="City2" />
</SelectField>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column tiny={3}>
<SelectField selectId="State2" required placeholder="Select" label={["City:"]} error={["Error message"]} isInvalid={this.state.reasonState} defaultValue={this.props.selectedValues[1]}>
<Select.Option value="City1" display="City1" />
<Select.Option value="City2" display="City2" />
</SelectField>
</Grid.Column>
</Grid.Row>
</Grid>
)}
/>
</ContentContainer>
);
}
}

The issue is, you are passing the prop selectedCodes and in the inner component you are using this.props.selectedValues. This should work.
constructor(props) {
super(props);
this.state = { reasonState: false, selectedValues: this.props.selectedCodes };
}

Related

this.setState does not update in Child when using a callback function to parent

I have a Select Form Child Component from which the user can choose multiple options. Every time the user makes a choice, a function handleChange is executed which calls the function changeExport from parent(passed as a prop to the child). changeExport then updates the parent state and handleChange finishes by updating the child state. The problem is that if the parent state is updated, the child state is not, but if I comment out the line which updates the parent state, child state is updated just fine.
This is the Parent.
class ExtendedTable extends React.Component {
constructor(props) {
super(props)
// columnJSON el format is { title: str, field: str, export: bool }
this.state = { dataJSON: [], columnJSON: [] }
this.changeExport = this.changeExport.bind(this)
}
changeExport(titles){
const newColumnJSON = JSON.parse(JSON.stringify(this.state.columnJSON));
newColumnJSON.forEach(col => {
if (titles.indexOf(col.title) >= 0) {
col.export = true
}
else {
col.export = false
}
})
this.setState({ columnJSON: newColumnJSON })
}
render(){return(
....
<MultipleSelect names={this.state.columnJSON.map(el=>el.title)} export={this.changeExport} />
)}
This is the child.
class MultipleSelect extends React.Component {
constructor(props){
super(props)
this.state = {
names:this.props.names,
column:[]}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
const arr = event.target.value.slice()
this.setState({column:arr})
this.props.export(arr)
}
render() { return(
<div>
<FormControl>
<InputLabel >Tag</InputLabel>
<Select
multiple
value={this.state.column}
onChange={this.handleChange}
input={<Input />}
renderValue={selected => selected.join(', ')}
MenuProps={MenuProps}
>
{this.state.names.map(col => (
<MenuItem key={col} value={col}>
<Checkbox checked={
this.state.column.indexOf(col) > -1}/>
<ListItemText primary={col} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
)};
}
What you are doing here—copying props to state—is warned against in the React documentation for this reason.
The linked page offers a number of alternatives. In your case I think you would be best served by making MultipleSelect a controlled component by eliminating state entirely and relying solely on props passed in. This might look something like this:
class MultipleSelect extends React.Component {
render() {
return (
<div>
<FormControl>
<InputLabel>Tag</InputLabel>
<Select
multiple
value={this.props.selected}
onChange={this.props.handleChange}
input={<Input />}
renderValue={selected => selected.join(", ")}
MenuProps={MenuProps}
>
{this.props.options.map(col => (
<MenuItem key={col} value={col}>
<Checkbox checked={this.props.selected.indexOf(col) > -1} />
<ListItemText primary={col} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
}

React - How to Populate one Dropdowns based on selection from another Dropdown by Passing State as props

I am creating a bar with two dropdown. The second dropdown depends of the selection from the first dropdown. I have 3 Components :
1. Dropdown Bar : Contains FirstDropdown and Second Dropdown
2. FirstDropdown
3. SecondDropdown
Trying to pass State -> Practice that appears in the FirstDropdown Component as props to SecondDropdown Component. Clearly I'm not doing this correctly. Any Help will be appreciate. Thank you in advance!
class DropdownBar extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<div>
<div className="top-bar">
<Row>
<div style={{marginTop: 15, marginBottom:15}}>
<Col span={8}><FirstDropdown practice={this.props.practice} /></Col>
<Col span={8}><SecondDropdown /></Col>
</div>
</Row>
</div>
</div>
)
}
class FirstDropdown extends React.Component {
constructor() {
super();
this.state = {
practices: [
name = 'Jon',
name = 'potato',
name = 'stark',
],
practice: 'stark'
}
}
onChangePractice(value) {
console.log(`selected ${value}`);
this.setState({
practice: value
})
}
render () {
const {practices} = this.state
return (
<div>
<Row>
<div className="First-dropdown">
<Col span={8}><div className="dropdown-title">Research: </div></Col>
<Col span={14}>
<Select
showSearch
style={{ width: '100%' }}
placeholder="Select a Something"
optionFilterProp="children"
onChange={this.onChangePractice.bind(this)}
onFocus={onFocus}
onBlur={onBlur}
onSearch={onSearch}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{practices.map(practice => (
<Option
value={practice}
key={practice}
data-automation={practice.name}
>{practice}</Option>
))}
</Select>
</Col>
</div>
</Row>
</div>
)
}
class SecondDropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
modules: [
name = 'Drogon',
name = 'Rhaegal',
name = 'Viserion',
]
}
}
componentDidUpdate(prevProps) {
console.log(this.props.practice)
if (!equal(this.props.practice, prevProps.practice))
{
this.updatePractice();
}
}
render () {
const {modules} = this.state
console.log(this.props.practice )
let practice = this.props.practice;
if (practice === 'stark') {
return (
<div>
<Row>
<div className="benchmark-dropdown">
<Col span={4}><div className="dropdown-title">Module: </div></Col>
<Col span={16}>
<Select
showSearch
style={{ width: '100%' }}
placeholder="Select Something"
optionFilterProp="children"
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
onSearch={onSearch}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{modules.map(item => (
<Option
value={item}
key={item}
>{item}</Option>
))}
</Select>
</Col>
</div>
</Row>
</div>
)
} else {
return <div> NOOOOO </div>
}
}
In order for both dropdowns to have access to the practice prop, you need to lift it up to the DropdownBar's state, and pass down both practice and a way to update practice.
class DropdownBar extends Component {
state = {
practice: '',
}
handlePracticeChange = (value) => {
setState({ practice: value });
}
render() {
return (
<div>
<FirstDropdown
practice={this.state.practice}
onPracticeChange={this.handlePracticeChange}
/>
<SecondDropdown practice={this.state.practice} />
</div>
)
}
}
So, practice only lives in DropdownBar, and the practices array should live in FirstDropdown child.
In FirstDropdown, you should pass props.onPracticeChange to your Select's onChange:
class FirstDropdown extends Component {
render() {
...
<Select
onChange={this.props.onPracticeChange}
...
}
}
From your code example, it looks like Select passes the currently selected value to onChange.
I'd pull the state into the parent.
class MainBar extends React.Component {
state = {
practice: null
};
handleChange = practice => {
this.setState({ practice });
}
render() {
return (
<div className="top-bar">
<Row>
<div style={{marginTop: 15, marginBottom:15}}>
<Col span={8}>
<FirstDropdown
onChange={this.handleChange}
practice={this.state.practice}
/>
</Col>
<Col span={8}>
<SecondDropdown practice={this.state.practice} />
</Col>
</div>
</Row>
</div>
);
}
}

Unable to send the updated value of state through props in react js

I am trying to send state value from parent to child component.Initially the state value is empty.After an API call,state value get updated but my props is taking the initial empty value.
class Metrics extends React.Component {
constructor(props) {
super(props);
this.state.result:[];
}
submit = e => {
e.preventDefault();
var URL =
"http://localhost:8080/fetchAnalysisData;
this.setState({ formsubmit: true });
fetch(URL, {
method: "GET"
})
.then(res => res.json())
.then(data => {
console.log("Response Success!!");
this.setState({ result: data });
});
};
render(){
return(
<Button onClick={this.submit}
fontSize: "small",
marginLeft: "30%"
}}
>
VIEW RESULT
</Button>
<div className={this.state.formsubmit ? "showDisplay" : "hide"}>
<DipslayBarChart result={this.state.result}></DipslayBarChart>
</div>
)
}
Child Component:
class DipslayBarChart extends React.Component {
constructor(props){
super(props);
}
render(){
return(
<div>
<BarChart width={500} height={300} data={this.props.result}>
<XAxis dataKey="Date" />
<YAxis />
<Tooltip cursor={false} />
<Legend />
<Bar dataKey="Success" stackId="a" fill="#068f12" label />
<Bar
dataKey="Failure"
stackId="a"
fill="#ec0b0b"
/>
</BarChart>
</div>
)
}
}
How to update the prop value once the state is updated?
Write your constructor like this,
constructor(props) {
super(props);
this.state={
result:[]
}
}
Moreover If you are not using the props in the constructor no need to declare constructor. you can declare state like this
state={
result:[]
}

How to show Data results on click in React?

I am trying to show my results from a JSON file only when the search button is clicked. What is the correct way to do it?
Right now as the user types a product the results are show. I have a simple filter, that is filtering the results, but I would like to make that only appear when the button is clicked. I only want to show results when the search button is clicked.
class App extends Component {
constructor(props){
super(props);
this.state = {
value: '',
list: []
}
this.handleChange = this.handleChange.bind(this);
this.handleSearch = this.handleSearch.bind(this);
this.refresh();
}
handleChange(event){
this.setState({ ...this.state, value: event.target.value })
}
refresh(){
axios.get(`${URL}`)
.then(resp => this.setState({...this.state, value: '', list: resp.data}));
}
handleSearch(product){
this.refresh();
}
render(){
return(
<div className="outer-wrapper">
<Header />
<main>
<Container>
<Row>
<Col xs={12} md={12} lg={12} className="pl-0 pr-0">
<SearchBar
handleChange={this.handleChange}
handleToggle={this.handleToggle}
handleSearch={this.handleSearch}
value={this.state.value}
/>
<SearchResultBar
value={this.state.value}
/>
<Filter />
</Col>
</Row>
<ProductList
value={this.state.value}
list={this.state.list}
/>
</Container>
</main>
</div>
)
}
}
export default App;
class Search extends Component {
constructor(props){
super(props);
}
render(){
return(
<div className="search-input">
<InputGroup>
<Input placeholder='Enter Search'
onChange={this.props.handleChange}
value={this.props.value}
/>
<InputGroupAddon className='input-group-append'
onClick={this.props.handleSearch}>
<span className='input-group-text'>
<i className="fa fa-search fa-lg fa-flip-horizontal"></i>
</span>
</InputGroupAddon>
</InputGroup>
</div>
)
}
}
export default Search;
class ProductList extends Component {
constructor(props){
super(props);
this.state = {
}
}
render(){
let filteredSearch = this.props.list.filter(
(product) => {
return product.title.indexOf(this.props.value) !== -1
}
)
return(
<Container>
<Row>
{
filteredSearch.map(item => {
return <Product {...item} key={item._id} />
})
}
</Row>
</Container>
);
}
}
export default ProductList;
As it stands, my list of products is being displayed in the app as soon as it loads. This seems something trivial, but I have been scratching my head in trying to solve it.
You're calling this.refresh() inside the constructor. So it gets run on mount.
Just remove it from the constructor and you should be fine.

react native - How to use state in constructor

I want to use a state in definition of an other state but i get nothing value.
Does anyone have any ideas??
constructor(props) {
super(props);
this.state = {
check : false,
datatotal : this.props.services.map((d) =>
<CheckBox
center
title={d}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checked= {true}
onPress={() => this.checkBoxClick()}
/>
)
};
}
You can use this inside your Component
constructor(props){
super(props);
this.state = {
check: false
}
}
render() {
<View>
{this.props.services && this.props.services.map(
<CheckBox
center
title={d}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checked= {true}
onPress={() => this.checkBoxClick()}
/>
)</View>}
}
Hey checkout this link it might help you : https://www.tutorialspoint.com/react_native/react_native_state.htm

Categories