How to add conditional statement to React data.map function - reactjs

I'm a React newbie and have a component which is outputting a checkbox list by mapping an array. This is the code that presently works.
export default class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: data,
};
}
render() {
return (
<div>
{this.state.data.map(d =>
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator"></div>
</label>)}
</div>
);
}
}
What I need to do is add an if/else telling the return map function only to render the checkbox list if another variable in the array (called domain) = "HMO". I'm really struggling with the syntax. I think it needs to be inserted below the {this.state.data.map(d => line but am really stuck. Any help would be greatly appreciated.

I believe you're looking for something like this.
export default class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: data,
};
}
render() {
return (
<div>
{this.state.data.map(d => {
if(d.domain === "HMO"){
return (
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator" />
</label>
)}
return null
})}
</div>
)
}
}
The .map function will iterate through each element in your data array, it will then check if that element's domain variable is equal to the string "HMO". If it is, it will return the html that displays the checkbox, otherwise it will return null.

Use Array.filter:
export default class First extends React.Component {
constructor(...args) {
super(...args);
this.state = {
data: data
};
}
getItems() {
return this.state.data
.filter(d.domain === "HMO")
.map(d => (
<label key={ d.name } className="control control--checkbox">{d.name}
<input type="checkbox"/>
<div className="control__indicator"></div>
</label>
));
}
render() {
return (
<div>
{this.getItems()}
</div>
);
}
}
The downside is that you loop twice compared to #MEnf's solution so it can be slower if you have a really long array. The upside is that it looks neater (I know that is quite subjective).

Related

Why is my class component not rendering correctly?

I've been at this awhile and I can't get my head around it. I feel so stupid. Can anyone tell me what's wrong?
The console log works currently, and the console.log of the Object states that the state has been updated from false to true.
class ChoiceBar extends React.Component {
constructor() {
super();
this.state = {
handleFirstQuestion: false,
};
this.handleFirstQuestion = this.handleFirstQuestion.bind(this)
}
handleFirstQuestion() {
console.log("Start Rendering First Question")
this.setState({handleFirstQuestion: true}, () => {console.log(this.state);
});
}
render() {
return (
<div>
<center>
<div>
<button onClick={this.handleFirstQuestion.bind(this)}> Start! </button>
<p> </p>
{this.state.handleFirstQuestion
? <FirstQuestionBox />
: null
}
</div>
</center>
</div>
)
}
}
The first thing is that you are binding the function twice, one in constructor and one in onClick event handler.
Second pass props component in constructor and super
constructor(props) {
super(props);
this.state = {
handleFirstQuestion: false,
};
this.handleFirstQuestion = this.handleFirstQuestion.bind(this)
}
return (
<div>
<center>
<div>
<button onClick={this.handleFirstQuestion}> Start! </button>
<p> </p>
{this.state.handleFirstQuestion
? <FirstQuestionBox />
: null
}
</div>
</center>
</div>
)
I don't think you are exporting the class component
write this after the class component
export default ChoiceBar;
you should probably use aero functions and useState hook instead of the class component
for example:
const ChoiceBar = () => {
const [handleFirstQuestion, setHandleFirstQuestion] = useState(false)
}

Passing props / state back to parent component in React JS

I have two components, a select list with several options and a button component
What I'd like to do in the UI is that the user can select any option from the select list they want and then press the button to reset the list to 'select'
I'm keeping the parent component as the one source of truth - all updated states are passed back to the parent component, I've actually got this working great in the context of one file with the following code;
class SelectList extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onSelectListChange(e.target.value);
}
render() {
const selectedValue = this.props.selectedValue;
log.debug('SelectListValue(): ', this.props.selectedValue);
return (
<select value={selectedValue} onChange={this.handleChange}>
<option value='One'>One</option>
<option value='select'>select</option>
<option value='Three'>Three</option>
<option value='Four'>Four</option>
<option value='Five'>Five</option>
</select>
);
}
}
class SelectListReset extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onResetChange('select');
}
render() {
return (
<div>
<button onClick={this.handleChange}>Reset list to select</button>
</div>
);
}
}
class Page extends Component {
constructor(props) {
super(props);
this.state={
selectedValue: 'select'
}
this.handleSelectedListChange = this.handleSelectedListChange.bind(this);
this.handleResetChange = this.handleResetChange.bind(this);
}
handleSelectedListChange(selectedValue) {
this.setState({selectedValue});
}
handleResetChange() {
this.setState({selectedValue: 'select'});
}
render() {
log.debug('render(): ', this.props);
log.debug('ParentListValue(): ', this.state.selectedValue);
return (
<div className="content-area">
<div className="container">
<h1>{LANGUAGES_CONTROLLER.format(this.props.languages, 'TitleSettings')}</h1>
<div>
<SelectList
onSelectListChange={this.handleSelectedListChange}
selectedValue={this.state.selectedValue}
/>
<SelectListReset
onResetChange={this.handleResetChange}
selectedValue={this.state.selectedValue}
/>
</div>
</div>
</div>
);
}
But what I've actually like to do is move the reset button to it's own file and this is where I fall over trying to pass the props / state back to the parent.
So the render method would actually look like this
render() {
log.debug('render(): ', this.props);
log.debug('ParentListValue(): ', this.state.selectedValue);
return (
<div className="content-area">
<div className="container">
<h1>{LANGUAGES_CONTROLLER.format(this.props.languages, 'TitleSettings')}</h1>
<div>
<SelectList
onSelectListChange={this.handleSelectedListChange}
selectedValue={this.state.selectedValue}
/>
<TestComponent
onResetChange={this.handleResetChange}
selectedValue={this.state.selectedValue}
/>
</div>
</div>
</div>
);
}
I import TestComponent and then inside of TestComponent is where I will have my code for the SelectListReset component but the problem I'm having is that now the values are sent to it as props which should be immutable right so can't be updated?
That's where my understand stops .. if someone can point me in the right direction on this I'd be very grateful!
Props received from a parent will change if the relevant state in the parent is changed. There's no problem with this and all the re-rendering is handled by React.
You can pass props down as many levels as you like.

How to remove an element in reactjs by an attribute?

I want to get unknown key attribute using known ID so that i may delete corresponding div.
I tried using document.getElementById("a").getAttribute('key'); , but it isn't working. May be my concept is wrong.
class PostAdded extends Component {
constructor(props) {
super();
this.deletepost = this.deletepost.bind(this);
}
deletepost() {
let ab =document.getElementById("a").getAttribute('key');
console.log(ab)
}
render() {
return (
<div>
{ this.props.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={this.deletepost}/>
</div>
) }
</div>
)
}
}
export default PostAdded;
If you were able to delete the div, that probably wouldn't end up working for you anyway because any state change would cause a re-render and it would appear again. Instead, you could keep track of your posts in state and then remove one of the posts from state in your deletepost method.
class PostAdded extends Component {
constructor(props) {
super();
this.state = {
posts: props.posts
}
this.deletepost = this.deletepost.bind(this);
}
deletepost(index) {
const newPosts = this.state.posts.splice(index)
this.setState({posts: newPosts})
}
render() {
return (
<div>
{ this.state.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={() => this.deletepost(i)}/>
</div>
) }
</div>
)
}
}
export default PostAdded;

Passing data and events between siblings in React

I'm trying to pass data from a search component to a result component. The idea is that the input from the search field in the search component will be sent to the result component and used as a parameter for an API-call when the search button is clicked.
I've based the data-flow structure on this article: https://codeburst.io/no-redux-strategy-for-siblings-communication-3db543538959, but I'm new to React and it's a bit confusing.
I tried using the parameter by directly getting it from props like so vinmonopolet.searchProducts({this.props.data}, but I got a syntax error.
I'm also unclear on how one would go about directing onClick events from one component to another.
Parent
class App extends Component {
constructor(){
super();
this.state = { data: '' }
}
fromSearch(param){
this.setState({
data: param
});
}
render() {
return (
<div className="App">
<Navbar />
<Searchbar callback={this.fromSearch.bind(this)} />
<ResultTable data={this.state.data}/>
</div>
);
}
}
Child1
class Searchbar extends React.Component{
getContent(event){
this.props.callback(event.target.value);
}
Searchbar.protoTypes = {
callback: ProtoTypes.func
}
render(){
return(
<div className="search-container">
<div className="search-field">
<input type="text" placeholder="Hva leter du etter?"
onChange={this.getContent.bind(this)}/>
<button type="button" onClick={???}>Search</button>
</div>
...
Child2
class ResultTable extends React.Component{
constructor(){
super();
this.state = {products: []}
}
searchAllProducts(){
const vinmonopolet = require('vinmonopolet')
vinmonopolet.searchProducts({this.props.data}, {sort: ['price', 'asc']}).then(response => {
const data = response.products;
const listItems = data.map((d) =>
<tr key={d.name}>
<td>{d.productType}</td>
<td>{d.name}</td>
<td>{d.price}kr</td>
</tr>
);
this.setState({products: listItems});
})
}
render(){
if(!this.state.products) return <p>Henter data...</p>;
return(
<div className="result-container">
<div className="result-table-header">
<table>
<th>Type</th>
<th>Varenavn</th>
<th>Pris</th>
</table>
</div>
<div className="result-table-body">
<table className="result-table">
{this.state.products}
</table>
</div>
</div>
);
}
}

How to setState for array immediately?

I ran into one problem connected with updating state in react.
Well, I have some data and I want to build a table with this data. But, I would like to filter it first. The filtration is working well, but I only have problem with updating filtered data and throwing it to the next component... (I know that setState is not working immediately...)
updatedReports in ReportTable component still has not filtered data...
What is the best way to fix it and to work with updating state for arrays.
export default class ReportContent extends React.Component {
constructor(props) {
super(props);
this.state = {
currentReports: this.props.reports
};
}
_filterBy(option) {
let updatedReports = [...this.props.reports].filter(report => {
if (report.organizations === option || report.reportType === option) {
return report;
}
});
console.log(updatedReports);
this.setState({currentReports: updatedReports});
}
render() {
return (
<div className="reports-table">
<ReportMenu organizations={this.props.organizations} reportTypes={this.props.reportTypes}
filterBy={this._filterBy.bind(this)}/>
<ReportTable updatedReports={this.state.currentReports}/>
</div>
);
}
}
You can maybe use the component lifecycle methods. Here is more info.
componentDidMount should do the trick. You can do something like this :
componentDidMount(){
let updatedReports = [...this.props.reports].filter(report => {
if (report.organizations === option || report.reportType === option) {
return report;
}
});
this.setState({currentReports: updatedReports});
}
Or just call your method _filterBy inside componentDidMount.
Hope this helps.
There's nothing wrong with the code you provided. setState should work if invoked correctly. My bet is the problem is within your other components or the data.
Here's a snippet that uses your code. I have no idea how you implement your other components so I just made some assumptions here.
class ReportMenu extends React.Component {
render() {
return <div className="well well-default">
<select className="form-control" onChange={(e) => {
this.props.filterBy(e.target.value)
}}>
<option> - </option>
{this.props.organizations.map(
(item, index) => <option key={index}>{item}</option>
)}
</select>
<br/>
<select className="form-control" onChange={(e) => {
this.props.filterBy(e.target.value)
}}>
<option> - </option>
{this.props.reportTypes.map(
(item, index) => <option key={index}>{item}</option>
)}
</select>
</div>
}
}
class ReportTable extends React.Component {
render() {
return <table className="table table-bordered">
<tbody>
{this.props.updatedReports.map(
(item, index) => <tr key={index}>
<td>{index}</td>
<td>{item.organizations}</td>
<td>{item.reportType}</td>
</tr>
)}
</tbody>
</table>
}
}
class ReportContent extends React.Component {
constructor(props) {
super(props);
this.state = {
currentReports: this.props.reports
};
}
_filterBy(option) {
let updatedReports = this.props.reports.filter(report => {
if (report.organizations === option || report.reportType === option) {
return report;
}
});
console.log(updatedReports);
this.setState({currentReports: updatedReports});
}
render() {
return (
<div className="reports-table">
<ReportMenu
organizations={this.props.organizations}
reportTypes={this.props.reportTypes}
filterBy={this._filterBy.bind(this)}/>
<ReportTable updatedReports={this.state.currentReports}/>
</div>
);
}
}
class App extends React.Component {
render() {
const reports = [
{
organizations: 'orgA',
reportType: 'typeA'
}, {
organizations: 'orgA',
reportType: 'typeB'
}, {
organizations: 'orgB',
reportType: 'typeA'
}, {
organizations: 'orgB',
reportType: 'typeB'
}
];
return <div className="container">
<h1 className="page-header">Reports</h1>
<ReportContent
reports={reports}
organizations={['orgA', 'orgB']}
reportTypes={['typeA', 'typeB']}/>
</div>
}
}
ReactDOM.render(<App/>, document.getElementById('root'));

Resources