React changing the state when the button is clicked - javascript

I am creating a react app where I want to output possible diseases if the symptoms button is clicked.
state = {
user_symptoms = [],
user_possible_disease = []
}
Disease = {
'aids': ['fever', 'cough', 'dysentery'],
'corona': ['fever', 'cough', 'breathe_problem'],
'heart_attack': ['angina', 'pain', 'head_ache'],
[A bunch of objects like this]
}
render() {
return(
<div>
<p>{{this.state.user_possible_disease.map((key, index) => {
return <h2 key={index}>{Object.keys(key)}</h2>
})}}</p>
<button value='cough' className='unclicked' />
<button value='angina' className='unclicked' />
<button value='pain' className='unclicked' />
<button value='breathe_problem' className='unclicked' />
</div>
)
}
So if I click any button of the symptoms, then the possible disease object with any of those symptoms will be added in the user_possible_dissease
Suppose I have clicked on the cough button so the user_possible_disease: [{'aids': ['fever', 'cough', 'dysentery'],
'corona': ['fever', 'cough', 'breathe_problem'],}] will be like this and if I unclick the button the possible diseases will be gone from the state.

I guess you wanted to show diseases for given symptoms. You can do the following:
class App extends React.Component {
state = {
user_symptoms: [],
user_possible_disease: [],
};
Disease = {
aids: ['fever', 'cough', 'dysentery'],
corona: ['fever', 'cough', 'breathe_problem'],
heart_attack: ['angina', 'pain', 'head_ache'],
};
toggleSymptom = (e) => {
let user_symptoms = this.state.user_symptoms;
if (user_symptoms.includes(e.target.value)) {
//we already have this symptom then remove it
user_symptoms = user_symptoms.filter(
(s) => s !== e.target.value
);
} else {
//we dont have the symptom so add it
user_symptoms = [...user_symptoms, e.target.value];
}
this.setState({
user_symptoms,
user_possible_disease: user_symptoms.length //do we have symptoms
? Object.entries(this.Disease) //look for deseases
.filter(([, diseaseSymptom]) =>
user_symptoms.every((
s //all symptoms are symptoms of disease
) => diseaseSymptom.includes(s))
)
.map(([key]) => key) //only need key of the object
: [],
});
};
render() {
return (
<div>
<ul>
{this.state.user_possible_disease.map((d) => (
<li key={d}>{d}</li>
))}
</ul>
<button
value="cough"
className="unclicked"
onClick={this.toggleSymptom}
>
cough
</button>
<button
value="angina"
className="unclicked"
onClick={this.toggleSymptom}
>
angina
</button>
<button
value="pain"
className="unclicked"
onClick={this.toggleSymptom}
>
pain
</button>
<button
value="breathe_problem"
className="unclicked"
onClick={this.toggleSymptom}
>
breathe problem
</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

First, I'd recommend storing the selected diseases in a JSON, instead of array.
state = {
user_possible_disease = {}
}
Then define the onButtonClick function:
onButtonClick (e) {
const disease = e.target.value;
const isActive = this.state.user_possible_disease[disease];
if (isActive) {
// Remove this disease from state;
const { [disease]: _, ...restDiseases } = this.state.user_possible_disease;
this.setState(restDiseases);
} else {
// Add this disease to state;
this.setState({
...this.state.user_possible_disease,
[disease]: Disease[disease]
})
}
}
And at last attach the onButtonClick function to each button:
<button
value='cough'
onClick={this.onButtonClick}
className={this.state.user_possible_disease['cough'] ? 'clicked' : 'unclicked'} />
Also one tip: Try not to duplicate any code/values. For example in the moment user clicks the button, we store the very same array of symptoms into the state. And that array exists both in the Disease constant AND in the state.
A better practice would be just to store the selected disease keys in thee state, like: ['aids', 'corona'], and then when user submits the form, to generate they request payload, by looping the selected diseases (from state), find their related symptoms and push them to they payload.
This way you lift off the component's state, e.g. it holds less data.

Add an onClick event to the button(s) and then set the right diseases based on the value of the clicked button.
const Disease = {
corona: ["fever", "cough", "breathe_problem"]
};
class App extends React.Component {
state = {
user_possible_disease: []
};
// This function will be called for all buttons
setPossibleDiseases = (event) => {
// The Disease[event.target.value] fetches the diseases from the Diseases object
this.setState({
user_possible_disease: Disease[event.target.value]
});
};
render() {
return (
<div>
<div>
{this.state.user_possible_disease.map((disease, index) => {
return <h2 key={index}>{disease}</h2>;
})}
</div>
<button
value="corona"
className="unclicked"
onClick={this.setPossibleDiseases}
>
Corona
</button>
</div>
);
}
}
In your example you have a { to much in {{this.state.user_poss.... and also an h2 cannot/should not be inside a p.

Related

how to add or remove tables dynamically in ReactJS

i want to add a table row by clicking Add, and remove a table row by clicking the small red div inside the table, while retaining the color change option when table is clicked on.
I've been trying for hours, but i'm still new to ReactJS, maybe someone could give me a hint, how to do this, for example with help of an array, a boolean or a for loop? I can't get the right way yet, would be thankful for your input.
i've been thinking about this kind of logic, but haven't been able to implement it yet..
{Boolean(this.state.rows.length) && (
<div onClick={this.handleRemoveRow}></div>
)}
https://jsfiddle.net/mattighof/0uop13kd/
Do the following:
Maintain a state say list and store all your items
Create onClick handlers for adding and removing items in the table
update the state when you add/remove
iterate and render this.state.list
Make sure to do event.stopPropagation() in the remove handler. this way your colour change functionality still works.
See here the implementation of adding and removing item
Code Snippet:
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
tableColor: true,
list: []
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
tableColor: !this.state.tableColor
});
}
addItem() {
this.setState({ list: this.state.list.concat("item") });
}
removeItem(e, index) {
e.stopPropagation();
this.setState({ list: this.state.list.filter((_, i) => index !== i) });
}
render() {
return (
<div className="container">
<button onClick={this.addItem} type="button">
Add
</button>
<table>
{this.state.list.map((item, index) => {
return (
<tr>
<td
className={this.state.tableColor ? "trRed" : "trBlack"}
onClick={this.handleClick}
>
{item}
<div
onClick={e => this.removeItem(e, index)}
className="innerDiv"
/>
</td>
</tr>
);
})}
</table>
</div>
);
}
}
This is one of the ways you can do it:
class Table extends React.Component {
constructor(props){
super(props)
this.state ={
rows:[{id:8,name:'item8',tablecColor:'trBlack'}],
tableColor: true
}
this.handleClick = this.handleClick.bind(this);
this.handleAdd = this.handleAdd.bind(this);
this.renderRows = this.renderRows.bind(this);
}
handleClick(clickedRow){
const {rows} = this.state;
let newRows = rows.map(row => {
if(row.id === clickedRow.id) {
row.tableColor = 'trRed'
return row
}
return row;})
this.setState({rows:newRows})
}
handleAdd() {
const {rows} = this.state;
const count = rows.length;
rows.push({id:count,name:count,tablecColor:'trBlack'})
this.setState({rows:rows})
}
renderRows() {
return this.state.rows.map(row => {
return (<tr>
<td className={row.tableColor}>
<div>{row.name}
<div onClick={() => this.handleClick(row)}
className="innerDiv">
</div>
</div>
</td>
</tr>)
});
}
render(){
return (
<div className="container">
<button type="button">Add</button>
<table>
{this.renderRows()}
</table>
</div>
)
}
}
ReactDOM.render(<Table />, document.querySelector("#app"));

Creating show and hide sections with buttons in reactjs

I have three buttons that when clicking show and individual div but this is done in reactjs
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.busButton = this.busButton.bind(this);
this.trainButton = this.trainButton.bind(this);
this.tramButton = this.tramButton.bind(this);
this.state = {
isHidden: false,
}
}
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={this.busButton}>Bus</button>
<button onClick={this.trainButton}>Train</button>
<button onClick={this.tramButton}>Tram</button>
{this.state.isHidden && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
</div>
)
}
}
export default ModeExtended
When I click any of the buttons it shows all bus, tram and train data - how do I get them to just show one thing at a time and making sure that the other states are closed. I am really missing something here and need a pointer or two or three…
How can I add an ID to make each button open separate from each other and when one is clicked how can I close the rest of the divs - or open state, I am so lost here. Please help me out.
Cheers as always!
Here is a REPL of my code:
You need to have 3 different isHidden properties to control your divs. You can do it like this:
this.state = {
isHiddenBus: false,
isHiddenTrain: false,
isHiddenTram: false,
}
and then in your render like this:
{this.state.isHiddenBus && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHiddenTrain && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHiddenTram && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
also your buttons have to change to state accordingly to this.
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenBus: !prevState.isHiddenBus
isHiddenTram: false
isHiddenTrain: false
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTrain: !prevState.isHiddenTrain
isHiddenBus: false
isHiddenTram: false
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTram: !prevState.isHiddenTram
isHiddenTrain: false
isHiddenBus: false
};
});
}
you can do somthing like this:
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.state = {
curDivIndex:0,//currently visible div index
// isHidden: false,
}
}
renderDiv=()=>{
switch(this.state.curDivIndex){
case 1:return <div> <h6>You can show Bus Data Now....</h6> </div>
case 2:return <div> <h6>You can show Train Data Now....</h6> </div>
case 3:return <div> <h6>You can show Tram Data Now....</h6> </div>
}
return null
}
setVisibleDiv=(index)=>{
this.setState({curDivIndex:index})
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={()=>{this.setVisibleDiv(1)} }>Bus</button>
<button onClick={()=>{this.setVisibleDiv(2)}}>Train</button>
<button onClick={()=>{this.setVisibleDiv(3)}}>Tram</button>
{this.renderDiv()}
</div>
)
}
}
export default ModeExtended
EDIT
you want to have three different buttons, on click of each certain div
needs to be visible.
you can achieve this by maintaining the index of currently visible div.
when user clicks any button you have to set the index of div to be visible
which in the above code is achieved by using setVisibleDiv(index) call.
and you can at rendering time use curDivIndex to decide visible div.
Or you can achieve this by declaring state properties for all case:
this.state = {
hiddenBus: false,
hiddenTrain: false,
hiddenTram: false,
}
providing a name attribute to your buttons like so:
<button name="hiddenBus" onClick={toggleDisplay}>Bus</button>
<button name="hiddenTrain" onClick={toggleDisplay}>Train</button>
<button name="hiddenBus" onClick={toggleDisplay}>Tram</button>
then by defining the toggleDisplay function to toggle their display:
toggleDisplay = (event) => {
event.preventDefault(); // default behavior of a clicked button is to send a form so let's prevent this
const { name } = event.target; // find the clicked button name value
this.setState((prevState => ({
[name]: !prevState[name],
}));
}
Setting[name] enables us to target the state prop via the nameattribute value and update it based on the previous state.
Try this
import React, { Component } from "react";
export default class Create extends Component {
constructor(props) {
super(props);
this.state = {
currentBtn: null
};
}
clickedButton = e => {
this.setState({ currentBtn: e.target.id });
};
showDivElem = () => {
const { currentBtn } = this.state;
switch (currentBtn) {
case "A":
return <div>A</div>;
break;
case "B":
return <div>B</div>;
break;
case "C":
return <div>C</div>;
break;
default:
return <div>ABC</div>;
break;
}
};
render() {
console.log(this.state.currentBtn);
return (
<div>
<button id="A" onClick={e => this.clickedButton(e)}>
A
</button>
<button id="B" onClick={e => this.clickedButton(e)}>
B
</button>
<button id="C" onClick={e => this.clickedButton(e)}>
C
</button>
{this.showDivElem()}
</div>
);
}
}

Push dynamically added html list item into last array

How can i push html into the last array. I was trying to add an item and supposed be add instantly into list array. The cod is working except I'm struggling to add new list into last array.
function addItem(id,name){
const array = JSON.parse(localStorage.getItem('categories'));
array.push({
name: name,
id:id,
});
//<li>{name}</li> push this into last array
localStorage.setItem('categories',JSON.stringify(array));
}
{categories.map(function(item, key){
return <div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id,'value name')}>Add</button>
</div>
})}
Something looks wrong in your example. I have added a complete exampl. You can maintain localStorage and State both. I hope this example helps you.
You mistake is that while adding new item you are pushing it to localStoage due to which react dom does not get rerendered. You have to update the value of state for that.
class App extends React.Component {
constructor() {
super();
this.state = {
categories: [
{
name: "Hello",
id: 1
},
{
name: "World",
id: 2
}
]
};
this.addItem = this.addItem.bind(this);
this.SaveToLocalStorage = this.SaveToLocalStorage.bind(this);
}
SaveToLocalStorage() {
const categories = this.state.categories;
localStorage.setItem("categories", JSON.stringify(categories));
}
addItem(id, name) {
const categories = this.state.categories;
categories.push({
name: name,
id: id
});
this.setState({ categories });
//localStorage.setItem("categories", JSON.stringify(categories));
}
render() {
let categories = this.state.categories;
const test = categories.map(item => (
<div key={item.id}>
<li>{item.name}</li>
</div>
));
return (
<div>
{test}
<button onClick={() => this.addItem(Date.now(), "Item")}>
Click to Add More
</button>
<button onClick={() => this.SaveToLocalStorage()}>
Save To LocalStorage{" "}
</button>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I guess this is what you are asking for. You just need to set it to state and re-render it when ever you are trying to add an element to list/array. I don't know why you are setting it to local storage but you can do it from state directly if your intention is to just store the previous array for future additions.
import React, { Component } from "react";
class App extends Component {
state = {};
constructor(props){
super(props);
this.state={
arr = []
}
}
addItem(id, name) {
const array = JSON.parse(localStorage.getItem("categories"));
array.push({
name: name,
id: id
});
//<li>{name}</li> push this into last array
localStorage.setItem("categories", JSON.stringify(array));
this.setState({arr:array});
}
renderList = () => {
return this.state.array.map(function(item, key) {
return (
<div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id, "value name")}>Add</button>
</div>
);
});
};
render() {
return <div>{this.renderList()}</div>;
}
}
export default App;

How can I grab the key of a list item generated from a map function?

So I am learning React, and I've tried searching for solutions to my problem both on stackoverflow and on React's own documentation, but I am still stumped.
Essentially, I have a list of 10 subreddits that is being mapped to list items in the form of the subredditsArray variable.
I render the results, and try to pass the selected item when I click that list item to my getSubredditInfo function. However, this doesn't work - event.target.key is undefined. (To clarify, I am looking to grab the key of the single list element that I have clicked).
When I try to just get event.target, I get the actual htmlElement (ex: <li>Dota2</li>), where as I want to get the key, or at least this value into a string somehow without the tags. I also tried putting my onClick method in the list tag of the map function, but that did not work.
Here is the relevant code:
//this is where I get my data
componentDidMount(){
fetch('https://www.reddit.com/api/search_reddit_names.json?query=dota2')
.then(results => {
return results.json();
})
.then(redditNames => {
//this is there I set my subreddits state variable to the array of strings
this.setState({subreddits: redditNames.names});
})
}
getSubredditInfo(event){
//console.log(event.target.key); <-- DOESNT WORK
}
render() {
var subredditsArray = this.state.subreddits.map(function(subreddit){
return (<li key={subreddit.toString()}>{subreddit}</li>);
});
return (
<div className="redditResults">
<h1>Top 10 subreddits for that topic</h1>
<ul onClick={this.getSubredditInfo}>{subredditsArray}</ul>
</div>
);
}
My questions essentially boil down to:
How do I grab the key value from my list object?
Additionally, is there a better way to generate the list than I currently am?
Thank you in advance.
EDIT: Added my componentDidMount function in hopes it clarifies things a bit more.
try the following code:
class App extends React.Component {
constructor(props){
super(props);
this.state = {subreddits:[]};
}
componentDidMount(){
fetch('https://www.reddit.com/api/search_reddit_names.json?query=dota2')
.then(results => {
return results.json();
})
.then(redditNames => {
//this is there I set my subreddits state variable to the array of strings
this.setState({subreddits: redditNames.names});
})
}
getSubredditInfo(subreddit){
console.log(subreddit);
}
render() {
return <div className="redditResults">
<h1>Top 10 subreddits for that topic</h1>
<ul>
{
this.state.subreddits.map((subreddit)=>{
return (<li key={subreddit.toString()} onClick={()=>this.getSubredditInfo(subreddit)}>{subreddit}</li>);
})
}
</ul>
</div>;
}
}
ReactDOM.render(
<App/>,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
please check the onClick event handler now. its an arrow function and its calling the getSubredditInfo function with your subreddit now. so you will get it there.
so its basically different way of calling the handler to pass data to the handler.
it works as you expect it to.
You can use lamda function or make component for item list which have own value for getSubredditInfo function
getSubredditInfo(value) {}
render() {
var subredditsArray = this.state
.subreddits.map((subreddit, i) =>
(<li key={i}
onClick={() => this.getSubredditInfo(subreddit)}>{subreddit}</li>));
return (
<div className="redditResults">
<h1>Top 10 subreddits for that topic</h1>
<ul>{subredditsArray}</ul>
</div>
);
}
1) Key should be grabbed either by the id in your object in array. Or you can combine the 2 properties to create a unique key for react to handle re-renders in a better way.
If you have a string array, you may use a combination of string value + index to create a unique value, although using index is not encouraged.
Given a quick example for both below.
2) A better way could be to move your map function into another function and call that function in render function, which will return the required JSX. It will clean your render function.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
subredditsObjArray: [
{ id: 1, value: 'A'},
{ id: 2, value: 'B'},
{ id: 3, value: 'C'},
{ id: 4, value: 'D'}
],
subredditsArray: ['A', 'B', 'C', 'D'],
selectedValue: ''
};
}
getSubredditInfo = (subreddit) => {
console.log(subreddit)
this.setState({
selectedValue: ((subreddit && subreddit.id) ? subreddit.value : subreddit),
});
}
render() {
return (
<div className="redditResults">
<p>Selected Value: {this.state.selectedValue}</p>
<h1>Top {this.state.subredditsArray.length || '0'} subreddits for that topic</h1>
<p>With Objects Array</p>
<ul>
{
this.state.subredditsObjArray
&& this.state.subredditsObjArray.map(redditObj => {
return (<li key={redditObj.id}><button onClick={() => this.getSubredditInfo(redditObj)}>{redditObj.value || 'Not Found'}</button></li>);
})
}
</ul>
<br />
<p>With Strings Array</p>
<ul>
{
this.state.subredditsArray
&& this.state.subredditsArray.map((reddit, index) => {
return (<li key={reddit + '-' + index}><button onClick={() => this.getSubredditInfo(reddit)}>{reddit || 'Not Found'}</button></li>);
})
}
</ul>
</div>
);
}
}
ReactDOM.render(
<App etext="Edit" stext="Save" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Are you trying to do this? I'm not sure what you want to do.
getSubredditInfo(e, subreddit) {
console.log(subreddit)
}
render() {
const { subreddits } = this.state
var subredditsArray = subreddits.map(subreddit => (
<li
key={subreddit.toString()}
onClick={(e) => {
this.getSubredditInfo(e, subreddit)
}}
>
{subreddit}
</li>
))
return (
<div className="redditResults">
<h1>Top 10 subreddits for that topic</h1>
<ul>{subredditsArray}</ul>
</div>
);
}
The key purpose is to pass your subreddit to the onClick function so you will receive the value while you click the item.
If you still get error try this and tell me what's happened.
render() {
const { subreddits } = this.state
var subredditsArray = subreddits.map(subreddit => (
<li
key={subreddit.toString()}
onClick={(e) => {
console.log(subreddit.toString())
}}
>
{subreddit}
</li>
))
return (
<div className="redditResults">
<h1>Top 10 subreddits for that topic</h1>
<ul>{subredditsArray}</ul>
</div>
);
}

Connect two dropdown filters to one search button

I have two dropdowns that are filtering, but they filter as you drop them down and make selections. I have a search button that I would like to hook them both to. So you just saw a change in results once, after you pressed the button. I think i have all the logic i need here But im not sure exactly how to hook up the button
note: i know i have alot of logic in the render, but im just trying to make it work first
So far this is what I have:
constructor(props) {
super(props);
this.state = {
developers: [],
filterCountry: "All locations",
filterSkills: "All skills"
};
}
componentDidMount() {
fetch('API')
.then(features => features.json())
.then(developers => {
this.setState({ developers })
})
}
filterCountry(e){
this.setState({filterCountry: e })
}
filterSkills(e){
this.setState({filterSkills: e })
}
render() {
let developers = this.state.developers.features
if (!developers ){
return null
}
if (this.state.filterCountry && this.state.filterSkills) {
developers = developers.filter( developer => {
return this.state.filterCountry === 'All locations' ||
developer.properties.continent.includes(this.state.filterCountry)
});
developers = developers.filter( developer => {
return this.state.filterSkills === 'All skills' ||
developer.properties.skills.includes(this.state.filterSkills)
});
}
return (
<div>
<div>
<ControlSelect
onChange={this.filterCountry.bind(this)}
value={this.state.filterCountry}
options={options_dd1}
/>
</div>
<div className="inline-block mr24">
<ControlSelect
onChange={this.filterSkills.bind(this)}
value={this.state.filterSkills}
options={options_dd2}
/>
</div>
<button>Search</button>
</div>
<div>
<div>
{developers.map(developer => {
return (
<div key={developer.id}">
{developer.properties.name}
{developer.properties.description}
{developer.properties.skills}
</div>
</div>
</div>
)}
)}
)
any help would be greatly appreciated
The main problem with what you have is that once the filtering is done, there is no way to get the original list of developers back. You can create an 'original list' or developers and a new filteredList, which could be actually used by the render method to show data.
Basically, in your initial render, the developers key in your state is the default loaded from fetch and will get rendered in its entirety. Once you click the button, the doSearch method will modify the state and remove developers. This will cause the render to be called and show the new filtered list.
Otherwise, there's a few minor things things taht I have commented below.
constructor(props) {
super(props);
this.state = {
developers: [],
filterCountry: "All locations",
filterSkills: "All skills"
};
}
componentDidMount() {
fetch('API')
.then(features => features.json())
.then(developers => {
this.setState({ developers })
})
}
filterCountry(e){
this.setState({filterCountry: e })
}
filterSkills(e){
this.setState({filterSkills: e })
}
doSearch() {
// Create copy of state (you had a `.filtered` in your code, which doesn't make sense as developers is an array so it will have no `filtered` property unless you modified the prototype
let developers = this.state.developers.slice()
// This if block is pointless, because you start with a default state in the constructor (so unless your ControlSelect have a falsy option, this will always evaluate to `true`)
if (this.state.filterCountry && this.state.filterSkills) {
// THis will match EITHER country OR skills. You can change to && if wanted.
developers = developers.filter( developer => {
return this.state.filterCountry === 'All locations' ||
developer.properties.continent.includes(this.state.filterCountry) || this.state.filterSkills === 'All skills'
|| developer.properties.skills.includes(this.state.filterSkills)
});
this.setState({ developers })
}
}
render() {
return (
<div>
<div>
<ControlSelect
onChange={this.filterCountry.bind(this)}
value={this.state.filterCountry}
options={options_dd1}
value={this.state.filterCountry}
/>
</div>
<div className="inline-block mr24">
<ControlSelect
onChange={this.filterSkills.bind(this)}
value={this.state.filterSkills}
options={options_dd2}
value={this.state.filterSkills}
/>
</div>
<button onClick={this.doSearch.bind(this)}>Search</button>
</div>
<div>
<div>
{/* Now the developers contains stuff that was filtered in search */}
{this.state.developers.map(developer => {
return (
<div key={developer.id}>
{developer.properties.name}
{developer.properties.description}
{developer.properties.skills}
</div>
</div>
</div>
)}
)}
)

Categories

Resources