I am working on a project using React and tailwind.
I would like to filter the options I mean I want see to at most 3 options. I tried slice but it is not a solution because using slice for instance if I type a I want to see at most 3 words which contains the letter a if I type b I want to see at most 3 words which contains the letter b and that words for a and b can be different so slice cannot be a solution.
Here is my code :
import React, { Component } from "react";
import Select, { components} from "react-select";
import { useState } from "react";
let cheeses = ["Wagasi", "Kalari", "Halloumi", "Manouri"];
let options = [];
options = options.concat(cheeses.map((x) => "Cheese - " + x));
const Foo = () => {
const [value, setValue] = useState("");
function MakeOption(x) {
if (value) {
return { value: x, label: x };
} else {
return { value: "", label: "" };
}
}
const handleInputChange = (value, e) => {
if (e.action === "input-change") {
setValue(value);
}
};
const Input = props => <components.Input {...props} maxLength={5} />;
return (
<Select
isMulti
name="colors"
options={options.map((x) => MakeOption(x)).filter(opt => opt.value !== "")}
className="basic-multi-select"
classNamePrefix="select"
closeMenuOnSelect={false}
onInputChange={handleInputChange}
inputValue={value}
noOptionsMessage={() => null}
/>
);
};
export default Foo;
Could you help me please ?
I think this code works like you want.
The problem have been solved with a second variable for the select options.
import React, { Component } from "react";
import Select, { components} from "react-select";
import { useState } from "react";
let cheeses = ["Wagasi", "Kalari", "Halloumi", "Manouri"];
let options = [];
options = options.concat(cheeses.map((x) => "Cheese - " + x));
const Foo = () => {
const [value, setValue] = useState("");
const [optionsToShow, setOptionsToShow] = useState([]);
function MakeOption(x) {
return { value: x, label: x };
}
const handleInputChange = (value, e) => {
if (e.action === "input-change") {
setValue(value);
const nextOptions = value ? options.map((x) => MakeOption(x)).filter((opt) => opt.label.toLowerCase().includes(value.toLowerCase())) : [];
setOptionsToShow(nextOptions.length > 3 ? nextOptions.splice(1,3) : nextOptions);
}
};
const Input = props => <components.Input {...props} maxLength={5} />;
return (
<Select
isMulti
name="colors"
options={optionsToShow}
className="basic-multi-select"
classNamePrefix="select"
closeMenuOnSelect={false}
onInputChange={handleInputChange}
inputValue={value}
noOptionsMessage={() => null}
/>
);
}
export default Foo;
I hope I've helped you
Related
I want to create a search bar with a list of results including the image and description of the product, I've tried with a datalist component but the html option tag does not allow any other element than text. This component takes the user input, fetch the data to the api and renders a list with the results.
This is my code:
import React, { useEffect, useState } from 'react'
import api from '../../utils/api'
import { baseUrl } from '../../utils/constants'
import styles from './searchBar.module.css'
const SearchBar = () => {
const [search, setSearch] = useState('')
const [results, setResults] = useState([])
useEffect(() => {
const getResults = async () => {
if (search.length > 2) {
try {
const response = await api.post('p/ver-productos', {
cuantos: 10,
filtros: {
nombre: [search],
},
})
if (
response.data.datos.items &&
response.data.datos.items.length > 0
) {
setResults(response.data.datos.items)
} else {
setResults([])
}
} catch (error) {
console.error(error)
setResults([])
}
}
}
getResults()
}, [search])
return (
<>
<input
className={styles.toolbarInput}
placeholder='Buscar productos'
list='results'
value={search}
onChange={e => setSearch(e.target.value)}
/>
<datalist id='results'>
{results.length > 0 &&
results.map((result: any) => {
return (
<option key={result.id}>
<img
src={baseUrl + result.multimedia[0].url}
alt={result.nombre}
/>
{result.nombre}
</option>
)
})}
</datalist>
</>
)
}
export default SearchBar
I assume when component is rendered multiple times something happens to setinterval,but how can i fix this.
bottom code is for Store that i am using and i don't understand.someone said that i must have useffect outside component but then it gives me error.
Anyways im new to react so i need help ,everyones appriciated.Thanks.
import SmallLogo from '../img/logo.svg';
import StarskyText from '../img/starskyproject.svg';
import './Statement.css'
import { BrowserRouter as Router,Routes,Route,Link } from "react-router-dom";
import { getElementError } from '#testing-library/react';
import react, { useRef , useState, useEffect } from 'react';
import { useDispatch, useSelector } from "react-redux";
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { store } from "./appReducer";
function TempText(props) {
return <span className="yellow changetext"> {props.body} </span>;
}
function doUpdate(callback) {
setInterval(callback, 1300);
}
export default function Statement(){
const dispatch = useDispatch();
const textOptions = ["NFT", "CRYPTO", "METAVERSE", "WEB3"];
const tempText = useSelector((state) => state.tempText);
function change() {
let state = store.getState();
const index = state.index;
console.log(index);
console.log(textOptions[index]);
dispatch({
type: "updatetext",
payload: textOptions[index]
});
let newIndex = index + 1 >= textOptions.length ? 0 : index + 1;
dispatch({
type: "updateindex",
payload: newIndex
});
}
useEffect(() => {
doUpdate(change);
}, []);
var [dropdownOpen , Setdrop] = useState(false);
return(
<div>
<Link to="/">
<img className='star-fixed' alt='starlogo' src={SmallLogo}></img>
</Link>
<img className='starsky-fixed' alt='starsky-project' src={StarskyText}></img>
<div className='text-content'>
<span className='statement-text'>WEB3 IS NOT ONLY THE FUTURE.
IT’S THE ONLY FUTURE!</span>
<span className='starsk-link'>starsk.pro</span>
</div>
<div className='text-content-bottom'>
<span className='statement-text-bottom'>CREATE YOUR NEXT
<TempText body={tempText} />
<span className='flex'> PROJECT WITH
<Dropdown className="hover-drop-out" onMouseOver={() => Setdrop(dropdownOpen=true) } onMouseLeave={() => Setdrop(dropdownOpen=false)} isOpen={dropdownOpen} toggle={() => Setdrop(dropdownOpen = !dropdownOpen) }>
<DropdownToggle className='hover-drop'> STRSK.PRO </DropdownToggle>
<DropdownMenu> </DropdownMenu>
</Dropdown> </span>
</span>
</div>
</div>
)
}
import { createStore } from "redux";
const initialState = {
tempText: "NFT",
index: 1
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "updatetext":
return {
...state,
tempText: action.payload
};
case "updateindex":
return {
...state,
index: action.payload
};
default:
return state;
}
};
export const store = createStore(reducer);
You can clear your timer by calling clearTimeout function with a reference to your timer when your component unmounting.
useEffect(() => {
const timer = setInterval(change, 1300);
// in order to clear your timeout
return () => clearTimeout(timer);
}, [])
I have found a code for a material table that accepts a list as input and applies pagination, sorting and filtering on it. The thing is I need to find a way to extract the data from the row onClick and redirect the page to a new route along with those data. How can I do that?
In the component, I call the table as follows:
export default function ViewAllUsers() {
const [filterFn, setFilterFn] = useState({ fn: items => { return items; } })
const records = ....//List of records
const {
TblContainer,
TblHead,
TblPagination,
recordsAfterPagingAndSorting
} = useTable(records, headCells, filterFn);
const handleSearch = e => {
let target = e.target;
//Handle search
}
return (
<>
<Paper className={classes.pageContent}>
<Toolbar>
<Controls.Input onChange={handleSearch}/>
</Toolbar>
<TblContainer>
<TblHead />
<TableBody>
{
recordsAfterPagingAndSorting().map(item =>
(<TableRow key={item.id}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.fullName}</TableCell>
</TableRow>)
)
}
</TableBody>
</TblContainer>
<TblPagination/>
</Paper>
}
and the useTable hook is:
export default function useTable(records, headCells, filterFn) {
const pages = [5, 10, 25]
const [page, setPage] = useState(0)
const [rowsPerPage, setRowsPerPage] = useState(pages[page])
const [order, setOrder] = useState()
const [orderBy, setOrderBy] = useState()
const TblContainer = props => (
<Table className={classes.table}>
{props.children}
</Table>
)
const TblHead = props => {
const handleSortRequest = cellId => {
//Some code
}
return (<TableHead>
<TableRow>
{
headCells.map(headCell => (
<TableCell key={headCell.id}
sortDirection={orderBy === headCell.id ? order : false}>
{headCell.disableSorting ? headCell.label :
<TableSortLabel
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : 'asc'}
onClick={() => { handleSortRequest(headCell.id) }}>
{headCell.label}
</TableSortLabel>
}
</TableCell>))
}
</TableRow>
</TableHead>)
}
const TblPagination = () => (
<TablePagination
component="div"
page={page}
rowsPerPageOptions={pages}
rowsPerPage={rowsPerPage}
count={records.length}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
id="TablePagination"
/>
)
return {
TblContainer,
TblHead,
TblPagination,
recordsAfterPagingAndSorting
}
}
You can simply use an onClick handler to pass the item data through it:
export default function ViewAllUsers() {
const [filterFn, setFilterFn] = useState({ fn: items => { return items; } })
const records = ....//List of records
const {
TblContainer,
TblHead,
TblPagination,
recordsAfterPagingAndSorting
} = useTable(records, headCells, filterFn);
const handleSearch = e => {
let target = e.target;
//Handle search
}
const handleItemClick = item => {
//Redirect to new route from here with the item data
}
return (
<>
<Paper className={classes.pageContent}>
<Toolbar>
<Controls.Input onChange={handleSearch}/>
</Toolbar>
<TblContainer>
<TblHead />
<TableBody>
{
recordsAfterPagingAndSorting().map(item =>
(<TableRow key={item.id} onClick={() => handleItemClick(item)}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.fullName}</TableCell>
</TableRow>)
)
}
</TableBody>
</TblContainer>
<TblPagination/>
</Paper>
</>
)
}
I want to create a tab bar that has tabs from a JSON file, and each of these tabs must have its own components. I used Reat-Tabs and made it as follows. But each panel is not shown
`
import React, { useState } from "react";
import "./toolbar.css";
import ToolbarData from "./toolbar.json";
import { makeStyles } from "#material-ui/core/styles";
import {Tabs,Tab,TabList,TabPanel} from "react-tabs";
import styled from "styled-components";
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
backgroundColor: theme.palette.background.paper,
},
}));
const ToolBar = (props) => {
const classes = useStyles();
const [key,setkey] =useState(0)
const isActive = (id) => {
return key === id;
};
const className = isActive ? 'active' : '';
const handleActive = (key) => {
setkey(key);
};
const CustomTab = ({ children }) => (
<Tab>
<div>{children}</div>
</Tab>
);
CustomTab.tabsRole = 'Tab';
const CustomTabPanel = ({ children, myCustomProp, ...otherProps }) => (
<TabPanel {...otherProps}>
<div>{children}</div>
{myCustomProp && `myCustomProp: ${myCustomProp}`}
</TabPanel>
);
CustomTabPanel.tabsRole = 'TabPanel'
const url = window.location.href.split("/").pop();
const vals = Object.keys(ToolbarData);
for (var i = 0; i < vals.length; i++) {
if (vals[i] === url) {
const list = vals[i];
return (
<div className="toolbar">
{Object.values(ToolbarData[list]).map((item,i) => (
<div className={classes.root}>
<Tabs
key={i}
isActive={isActive(item.id)}
onActiveTab={() => handleActive(item.id)}
>
<TabList>
<CustomTab className={className} isActive={props.isActive} onClick={props.onActiveTab}> {item.name}</CustomTab>
</TabList>
</Tabs>
<CustomTabPanel children={item.name} />
</div>
))}
</div>
);
}
}
};
export default ToolBar;
The information comes right from the Json file and I get the components of each tab from somewhere else. I tried different solutions but did not come to a conclusion
I would like, as I've said on the title, change the state of my button "Annuler" when I reach a certain value of "tab" variable. I obviously verified if my problem weren't similar to another person but I didn' found at all. I also tried to use an arrow function in order to return the value of true or false for some conditions. Also tried with the code below by using "something ? true : false" format. I must necessarily use a function instead of class. Here's my code :
import { StyleSheet , View , ScrollView , Image , Text , FlatList , TouchableHighlight, StatusBar, Button, Alert} from 'react-native';
import * as Font from 'expo-font';
import Header from './components/Header';
import Footer from './components/Footer';
import { AppLoading } from 'expo';
import modulesData from './Helpers/modulesData.js';
export default function App() {
...
var tab = 0;
var arr = Array(3);
var arrstring = arr.toString()
var i = 0
var classModules = (module) => {
arr[tab] = module;
arr.length = 3;
tab++;
if (tab == 3){
var arrstring = arr.toString()
Alert.alert("Les modules sélectionnés sont :",arrstring);
}
}
var unfillarray = () => {
if (tab => 3)
{
arr = ['','','']
tab = 0;
}
}
var disablebutton = false;
if(fontsLoaded){
return (
...
<FlatList contentContainerStyle={styles.Flatlist}
data={modulesData}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) =>
<TouchableHighlight style={styles.DivModule}
onLongPress={() => Alert.alert("Description du "+modulesData[item.id - 1].title+" : ",modulesData[item.id - 1].overview)}
onPress={() => {classModules(modulesData[item.id -1].title)}}
underlayColor="#D8DFE3">
<Text style={{fontSize:16}}>{item.title}</Text>
</TouchableHighlight>
}
/>
<Button title="Annuler" style={{height:50}} color="#FFD48E" onPress={() => {unfillarray()}} disabled={tab == 3 ? false : true }>
<Text style={{color:"black"}}>
Annuler
</Text>
</Button>
</View>
);
} else {
return (
...
);
}
}
const styles = StyleSheet.create({
HeaderInfoText:{
...
},
HeaderInfo:{
...
},
Flatlist:{
...
},
DivModule:{
...
}
})```
I think you need to play with the state like this call this function or simply update state:
this.state{
isDisabled: false
}
handleChange = () => {
this.setState({ isDisabled: !this.state.isDisabled})
}