Dynamically disable button when a variable reachs a value - function

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})
}

Related

How to limit the number of options in a select?

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

React : i have following code, i am using setInterval to change text value time to time ,when i switch pages and come back text is changing reallyfast

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);
}, [])

React js material ui core table get data from row on click

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>
</>
)
}

Update state in class from const

I'm new to React JS and I'm coding a really simple task manager. So, I have all tasks in state element of MyTodoList class (each task has: id, name, description, completed). Then I draw each task separately with Task constant.
I want to implement changing buttons below every task (if task is completed button should be "Done", if not - "Not done").
I do not understand how I can update "completed" attribute (which is in MyTodoList class in state) from const Task.
Would be grateful for any hint!
Code:
import logo from './logo.svg';
import './App.css';
import React from 'react';
function DoneButton({onClick}) {
return (
<button onClick={onClick}>
Done
</button>
);
}
function NotDoneButton({onClick}) {
return (
<button onClick={onClick}>
Not done
</button>
);
}
const Task = ({id, name, description, completed}) => {
const handleDoneClick = () => {
completed= false //something different should be here
}
const handleNotDoneClick = () => {
completed= true //something different should be here
}
let button;
if (completed) {
button = <DoneButton onClick={handleDoneClick} />
} else {
button = <NotDoneButton onClick={handleNotDoneClick} />
}
return (
<div className='task'>
<h3>{name}</h3>
<div>{description}</div>
<div>{completed}</div>
{button}
</div>
)
}
class MyTodoList extends React.Component {
state = {
tasks: [
{
id: 1,
name: 'Walk the dog',
description: 'Have to walk the dog today',
completed: false,
},
],
}
render () {
return(
<div>
<header><h1>TO-DO</h1></header>
<div>{this.state.tasks.map(task => <Task id={task.id} name={task.name}
description={task.description} completed={task.completed}/>)}
</div>
</div>
)
}
}
const App = () => {
return (
<MyTodoList />
)
}
export default App;
You should never re-assign parameters unless it is the only solution you have, but you should definitely never re-assign parameters which you plan to depend on in the render method.
The proper solution would be this:
import React, { useState } from 'react';
...
const Task = ({ id, name, description, completed }) => {
const [isCompleted, setIsCompleted] = useState(completed);
const handleDoneClick = () => {
setIsCompleted(true);
};
const handleNotDoneClick = () => {
setIsCompleted(false);
};
let button;
if (isCompleted) {
button = <DoneButton onClick={handleDoneClick} />;
} else {
button = <NotDoneButton onClick={handleNotDoneClick} />;
}
return (
<div className="task">
<h3>{name}</h3>
<div>{description}</div>
<div>{isCompleted}</div>
{button}
</div>
);
};
You need to use local state, in which you will set the initial value (completed, or not completed) which you are receiving from props, and then change the state, and not the parameter. Furthermore, continue using the state value of your completed (isCompleted) so React will react to its change.
This is not the final solution though, as this will only keep the local change of the task, and not change the task status in tasks list.
Basically, if you component A holds the tasks and their complete status, you need to create a method in the component A which will modify the respective task by ID, to the correct status. Then you need to pass the respective method to component B which will call the method and pass along the id and complete status (true / false) The method which is assigned in component A will then look through the list of tasks, find the proper task by ID, and assign its new completed value you passed from component B. After that, react does its thing and automatically updates completed prop you passed to component B
Working snippet:
function DoneButton({ onClick }) {
return <button onClick={onClick}>Done</button>;
}
function NotDoneButton({ onClick }) {
return <button onClick={onClick}>Not done</button>;
}
const Task = ({ id, name, description, completed, onTaskClick }) => {
const handleDoneClick = () => {
onTaskClick(id, false);
};
const handleNotDoneClick = () => {
onTaskClick(id, true);
};
let button;
if (completed) {
button = <DoneButton onClick={handleDoneClick} />;
} else {
button = <NotDoneButton onClick={handleNotDoneClick} />;
}
return (
<div className="task">
<h3>{name}</h3>
<div>{description}</div>
<div>{completed}</div>
{button}
</div>
);
};
const MyTodoList = () => {
const [tasks, setTasks] = React.useState([
{
id: 1,
name: 'Walk the dog',
description: 'Have to walk the dog today',
completed: false,
}
]);
const onTaskClick = React.useCallback(
(id, isCompleted) => {
const updatedTasks = [...tasks].map((task) => {
if (task.id === id) {
return {
...task,
completed: isCompleted,
};
}
return task;
});
setTasks(updatedTasks);
},
[tasks]
);
return (
<div>
<header>
<h1>TO-DO</h1>
</header>
<div>
{tasks.map((task) => (
<Task onTaskClick={onTaskClick} id={task.id} name={task.name} description={task.description} completed={task.completed} />
))}
</div>
</div>
);
};
const App = () => <MyTodoList />;
ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

A tab bar whose tabs are created from a JSON file and each of these tabs must have its own components

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