My simple app has:
- data: array of objects
- users, setUsers: useState hooks
- filters: array of strings
- filteredUsers: it should be an array of objects;
In my app, a user can click and add a string to an array of filters (filters changing), then I'd like to create a new arr of objs filteredUsers, send it to users (by setUsers(filteredUsers)) and render a new list, based on filters.
When I'm using a single string, e.g. getFilteredUsers('string') it works, but I can't make it with an array.
const users = [
{
id: 849,
name: 'John',
city: 'London',
languages: ['English']
},
{
id: 294,
name: 'Ola',
city: 'Stockholm',
languages: ['Swedish', 'English']
},
{
id: 585,
name: 'Stefano',
city: 'Naples',
languages: ['Italian', 'French']
},
{
id: 946,
name: 'Anna',
city: 'Paris',
languages: ['French']
}
]
const four = document.querySelector('.four');
const arrayFilter = arr => {
const newUsers = filters.map(filter => getUsers(filter));
four.textContent = JSON.stringify(newUsers);
return newUsers
}
const test = ['French'];
console.log(arrayFilter(test))
I've also tried to use useEffect, but with no results.
jsfiddle: https://jsfiddle.net/gmp5doqv/165/
GitHub: https://github.com/lukaasz555/job-list/blob/main/components/Main/Main.tsx
CodePudding user response:
This is a function to check a user passes a filter :
const checkUser = (user, filter) =>
user.name === filter || user.city === filter || user.languages.includes(filter);
This is a function that check a user passes all filters :
let filters = null;
const userFilter = user => {
for(let i = 0, l = filters.length ; i < l ; i ) {
if(!checkUser(user, filters[i])) {
return false;
}
}
return true;
}
And this is how you can use it :
filters = ['French', 'Naples'];
filteredUsers = users.filter(userFilter);
// gives Stefano, the only one with French and Naples
filters = ['English'];
filteredUsers = users.filter(userFilter);
// gives John and Ola, the only ones with English
filters = [];
filteredUsers = users.filter(userFilter);
// gives everyone !
filters = ['Portuguese'];
filteredUsers = users.filter(userFilter);
// gives no one
CodePudding user response:
Here is an example of preforming this filter using React and the array methods .some
and .includes
// Get a hook function
const { useState } = React;
function App() {
const users = [
{
id: 849,
name: 'John',
city: 'London',
languages: ['English']
},
{
id: 294,
name: 'Ola',
city: 'Stockholm',
languages: ['Swedish', 'English']
},
{
id: 585,
name: 'Stefano',
city: 'Naples',
languages: ['Italian', 'French']
},
{
id: 946,
name: 'Anna',
city: 'Paris',
languages: ['French']
}
];
const languages = [
'English',
'Swedish',
'Italian',
'French'
];
const [selectedLangs, setSelectedLangs] = useState(
Object.fromEntries(languages.map(s => [s, false]))
);
function handleCheckboxClick({target}) {
const { value, checked } = target;
const selectedClone = structuredClone(selectedLangs);
const state = selectedClone[value];
selectedClone[value] = !state;
setSelectedLangs(selectedClone);
}
const selectedLangsThatAreTrue = Object.entries(selectedLangs)
.filter(([lang, val]) => val)
.map(([lang]) => lang);
const targetData = users.filter(
({languages}) =>
languages.some(lan => selectedLangsThatAreTrue.includes(lan))
);
return (
<div className="App">
Select Languages:
{
languages.map(s => (
<label key={s}> {s}
<input value={s}
onClick={handleCheckboxClick}
type="checkbox" />
</label>
))
}
<br />
{
targetData.map(({name}) => <span key={name}> {name} </span>)
}
</div>
);
};
// Render it
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
.App label {
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>