In my project I want to access the name of student after clicking the present button .
So it means if I click on "arijit" name then it should log on console "arijit"
const StudentList = () => {
const [studentlist, setStudentList] = useState([]);
const studentdataList = async () => {
const result = await fetch("http://localhost:5000/api/students");
const studentResult = await result.json();
setStudentList(studentResult);
console.log(studentResult[0].name);
};
function present(){
// what to write here?
}
useEffect(() => {
studentdataList();
},[]);
return (
<div>
{studentlist.map((student) => {
return (
<Card style={{ width: "18rem" }}>
<Card.Body>
<Card.Title> {student.name} </Card.Title>
<Button onClick={present}>present</Button>
<Button>abscent</Button>
</Card.Body>
</Card>
);
})}
</div>
);
};
export default StudentList;
The simplest solution would be to pass the student's name into the present function inside of the onClick handler.
const StudentList = () => {
const [studentlist, setStudentList] = useState([]);
const studentdataList = async () => {
const result = await fetch("http://localhost:5000/api/students");
const studentResult = await result.json();
setStudentList(studentResult);
console.log(studentResult[0].name);
};
function present(name){
console.log(name);
}
useEffect(() => {
studentdataList();
},[]);
return (
<div>
{studentlist.map((student) => {
return (
<Card style={{ width: "18rem" }}>
<Card.Body>
<Card.Title> {student.name} </Card.Title>
<Button onClick={() => present(student.name)}>present</Button>
<Button>abscent</Button>
</Card.Body>
</Card>
);
})}
</div>
);
};
export default StudentList;
Related
I have a list of menu categories displayed in my app. On Hover, I want to use a popper to get the subcategories that belongs to the category and display on the popper.
Here I have the states declared and once page loads, I populate the categories and subcategories from the db.
const [categories, setCategories] = useState([])
const [subCategories, setSubCategories] = useState([])
const [placement, setPlacement] = useState()
const [categorySub, setCategorySub] = useState([])
const [anchorEl, setAnchorEl] = React.useState(null)
const handlePopoverOpen = (e) => {
setAnchorEl(e.currentTarget)
}
const handlePopoverClose = () => {
setAnchorEl(null)
}
const open = Boolean(anchorEl)
const id = open ? 'simple-popper' : undefined
useEffect(() => {
loadCategories()
loadSubCategories()
}, [])
const loadCategories = async () => {
const res = await getAllCategories()
setCategories(res.category)
}
const loadSubCategories = async () => {
const res = await getAllSubCategories()
setSubCategories(res.subCategory)
}
Then I create a function that should filter the subCategories based on the categories
const getSub = (categoryId) => {
const sub = subCategories.filter((a) => a.parent === categoryId)
const data = sub.map((s) => s.name)
setCategorySub(data)
}
Here's what gets returned.
here, I display the menu categories. but I am having issues running the function to display on the popper.
Don't know how to call. the getSub() function, passing the category ID before displaying the popper. Is there a better way of resolving this?
return (
<Paper>
<MenuList>
<MenuItem>
<Typography variant='h6' component='body'>
ALL CATEGORIES
</Typography>
</MenuItem>
<Divider />
{categories &&
categories.map((category) => (
<>
<MenuItem
key={category._id}
sx={{ pl: 4 }}
aria-describedby={id}
onMouseOver={() => {
getSub(category._id)
}}
onMouseEnter={handlePopoverOpen}
onMouseLeave={handlePopoverClose}
>
<Typography>{category.name}</Typography>
</MenuItem>
<Divider />
<Popper
id={id}
open={open}
anchorEl={anchorEl}
placement='right'
>
<Box sx={{ border: 1, p: 1, bgcolor: 'background.paper' }}>
{categorySub.map((item) => (
<Typography>{item.name}</Typography>
))}
</Box>
</Popper>
</>
))}
</MenuList>
</Paper>
So I have a functional components here:
export default function Test() {
const [products, setProduct] = useState<any>([]);
const [image, setImage] = useState<any>([""]);
const [prices, setPrice] = useState<any>([]);
const [showPrice, setShowPrice] = useState<boolean>(false);
const [PhonePrice, setPhonePrice] = useState<any>("");
useEffect(() => {
async function loadProducts() {
const res = await fetch("http://raw.githubusercontent.com/reborn094/Practice/main/data.json", {
method: "GET",
});
const json = await res.json();
const data = json.products;
setProduct(data);
return (
<div>
{products.map((product: any, index: number) => {
return (
<Col>
<Card key={index} style={{ width: "20rem" }}>
<Card.Body>
<Card.Title>
</Card.Title>
<Card.Title>
<Child ProductImage={image[index]} name={product.name} code={product.code} onSelectProduct={()=>{
>
what should I write here????
------------------------
}}
></Child>
</Card.Title>
<Card.Text></Card.Text>
</Card.Body>
</Card>
</Col>
);
})}
</div>
);
}
And here is my Child components :
export default function Child(props:{
onSelectProduct?:()=> void;
}) {
return (
<div>
<Button onClick={props.onSelectProduct}></Button>
</div>
)
}
My question is What if I want to set button in Test components to target single item in list, what should I do? Because Now If I set Button that Button would trigger all item.What should I do in the function onSelectProduct?
So basically I have 2 pieces, the sidebar, then the opener. I'm trying to setup a ref that will connect the sidebar to the current opener. The opener is a functional component, and no matter what I do the current value is null. Am I missing something? I'm just trying to resize a component. My goal is to be able to resize the shown sidebar with the opener.
Here's part of the Render function.
render() {
const { selected, isSidebar, selectedType, search, active } = this.state;
const { pending, callback, resource } = this.props;
const pendingLengh = pending ? pending.length : 0;
const callbackLength = callback ? callback.length : 0;
const isResource = !resource || !Object.keys(resource).length;
return (
<div className="newPatientPage mainPage">
{this.renderMetadata()}
<SubTopBar
title="New Patient Processing"
noLeftSide={true}
subStatus={this.getStatus(pendingLengh, callbackLength)}
isBarcode={!isResource}
sideComponent={this.renderSideComponent()}
/>
{
active ?
<SnapshotSideBar
ref={this.sidebarRef}
patientResource={this.props.patientResource}
isShow={isSidebar}
settup={this.state.settup}
isScan={true}
handleCloseSidebar={this.handleCloseSidebar}
/> :
<NewPatientSideBar
ref={this.sidebarRef}
stepProps={this.state.stepProps}
selected={selected}
isShow={isSidebar}
handleCloseSidebar={this.handleCloseSidebar}
/>
}
<SidebarExtension sidebarToggle={this.toggleSidebar} sidebarReference={this.sidebarRef} sidebarState={isSidebar}/>
Here's the SidebarExtension component
const SidebarExtension = ({
sidebarToggle,
sidebarReference,
sidebarState,
...restProps
}) => {
const [xPos, setXPos] = useState(0);
const [width, setWidth] = useState();
const [openerPosition, setOpenerPosition] = useState(50);
const [isOpen, setIsOpen] = useState(false);
const toggleSidebar = () => {
sidebarToggle();
setIsOpen(!isOpen);
};
useEffect(() => {
setIsOpen(sidebarState);
}, [sidebarState])
if ((!isOpen && !sidebarState)) {
return (
<>
<div
className="resizeHandle"
style={{
right: "0Px",
}}
onClick={toggleSidebar}
>
<LeftCharvenSVG />
</div>
</>
);
}
return (
<>
<div
className="resizeHandle active"
onClick={toggleSidebar}
onMouseDown={startResize}
>
<LeftCharvenSVG />
</div>
</>
);
};
export default SidebarExtension;
Here's what the constructor looks like.
Main Constructor
From the docs https://reactjs.org/docs/forwarding-refs.html you need to wrap your functional component in React.forwardRef()
Example
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
In your case that would be:
const SidebarExtension = React.forwardRef(({
sidebarToggle,
sidebarReference,
sidebarState,
...restProps
}, ref) => {
const [xPos, setXPos] = useState(0);
const [width, setWidth] = useState();
const [openerPosition, setOpenerPosition] = useState(50);
const [isOpen, setIsOpen] = useState(false);
const toggleSidebar = () => {
sidebarToggle();
setIsOpen(!isOpen);
};
useEffect(() => {
setIsOpen(sidebarState);
}, [sidebarState])
if ((!isOpen && !sidebarState)) {
return (
<>
<div
className="resizeHandle"
style={{
right: "0Px",
}}
ref={ref}
onClick={toggleSidebar}
>
<LeftCharvenSVG />
</div>
</>
);
}
return (
<>
<div
className="resizeHandle active"
onClick={toggleSidebar}
onMouseDown={startResize}
>
<LeftCharvenSVG />
</div>
</>
);
});
export default SidebarExtension;
I am making a watchlist component using redux/react/hooks. Component is in 3 pieces (form to add to list, container to map over securities, and security to display each item)
So far I have been able to add values by dispatching addStock in the form component. I tried to do the same thing in security component for deleteStock but it isn't working/ reloads page.
reducer:
const stockSelector = (state = STOCK_STATE, action) => {
switch (action.type) {
case STOCK_SELECTED:
return action.payload;
case FETCH_STOCK_LIST:
return { ...state, watchlist: action.payload.select, title: action.payload.name, loading: false};
case STOCK_LIST_LOADING:
return {...state, loading: true}
case ADD_STOCK:
return { ...state, watchlist: [action.payload, ...state.watchlist] };
case DELETE_STOCK:
return {
...state,
watchlist: [
...state.watchlist.slice(0, action.payload),
...state.watchlist.slice(action.payload + 1)
],
};
default:
return state;
}
action
export const deleteStock = (payload) => ({
type: DELETE_STOCK,
payload,
});
watchlist component
const Watchlist = ({selected, watchlists, number}) => {
const dispatch = useDispatch();
const [taskList, setTaskList] = useState(['AAPL', 'MSFT', 'AMZN'])
const [list, setList] = useState(selected)
const [allList, setAllList] = useState(watchlists)
const [selectNumber, setSelectNumber] = useState(number)
const selectWatchlist = async () => {
setList(selected)
setSelectNumber(number)
}
useEffect(() => {
selectWatchlist()
.then(dispatch(fetchStockList(selectNumber)))
}, []);
return (
<React.Fragment>
<Col className="watchlist-master-col">
<Row className="watchlist-form-row">
<Col>
<AddWatchlistForm className="watchlist-form" />
</Col>
</Row>
<Row className="watchlist-list-row">
<ListSecurityContainer
list={taskList}
className="watchlist-list"
number={number}
/>
</Row>
<Row>
<Modal className='modalOne' />
</Row>
</Col>
<Modal />
</React.Fragment>
)
}
const mapStateToProps = (state) => {
console.log(state)
return {
selected: state.Watchlist.stock.title,
watchlists: state.Watchlist.watchlist.watchlist,
watchlist: state.Watchlist.stock.watchlist,
number: state.Watchlist.watchlist.number,
}
}
container
const ListSecurityContainer = ({loading, stocks}) => {
const dispatch = useDispatch();
const handleCloseTask = (id) => {
dispatch(deleteStock(id))
}
if (loading === false) {
return (
<React.Fragment>
<Col>
{stocks.map((value, index) => (
<Security
key={stocks[index]}
id={index}
{...value}
name={value}
// onClose={handleCloseTask}
className="security-elem"
/>
))}
</Col>
</React.Fragment>
);
}
return <div>Loading...</div>
}
const mapStateToProps = (state) => {
console.log(state.Watchlist.stock.watchlist)
return {
stocks: state.Watchlist.stock.watchlist,
loading: state.Watchlist.stock.loading
}
}
security
const Security = (value) => {
const dispatch = useDispatch();
const [taskName, setTaskName] =useState(value.name)
const removeTask = () => {
dispatch(deleteStock(taskName))
}
return (
<div className="list-group-item">
{value.name}
<button onClick={removeTask()} style={{ float: 'right' }}>
<i className="glyphicon glyphicon-remove"></i>
</button>
</div>
);
}
Fixed this by correcting the issues listed in the comments and also fixing a type that I had in my constants.js file.
const Security = ({index, name}) => {
const dispatch = useDispatch();
const [taskName, setTaskName] =useState(name)
const removeTask = (e) => {
e.stopPropagation()
dispatch(removeStock(index))
}
return (
<Row className="list-group-item">
<div className="item-titles">
{name}
</div>
<button onClick={() => dispatch(removeStock(index))} className="remove-item">
<i className="glyphicon glyphicon-remove"></i>
</button>
</Row>
);
}
I am trying to get an action to be available within a function that is called within array.map. Passing the props from parent component to subcomponent is happening. It feels like it should be a simple task to make it available within the array.map function, but that has not proven successful.
Here's an updated example code:
In this example, being able to properly pass the 'actionUpdate' function to listItem is what I have not accomplished successfully.
function listItem(item,index) {
const id = item.id
const handleUpdated = e => {
e.preventDefault();
actionUpdate(id);
};
return (
<Button
onClick={handleUpdated}
color='primary'
variant='contained'
style={{ marginTop: '0.75rem' }}
>
Update
</Button>
);
}
function MyList(props) {
const { streams } = props;
return (
<List>
{streams.map(listItem)};
</List>
);
}
function listView(props) {
const { classes, streams } = props;
return (
<div style={{ width: '100%' }}>
<section className={classes.content}>
<Grid container>
<Grid item style={{ width: '100%' }}>
<MyList
streams={streams}
actionUpdate={actionUpdate}
/>
</Grid>
</Grid>
</section>
</div>
);
}
const mapStateToProps = state => {
const streams = R.path(['theObject', 'arrayOfObjects'])
)(state);
return { streams };
};
const mapDispatchToProps = dispatch => {
const actionUpdate = (itemId) => {
return dispatch(theUpdateAction(itemId));
};
return { actionUpdate };
};
const MainListView = connect(
mapStateToProps,
mapDispatchToProps
)(listView);
export default withStyles(styles)(MainListView);
I have my state and actions mapped to props using connect, mapStateToProps and mapDispatchToProps.
What I need to achieve is having access to the action from the dispatch within the listItem function.
You could define listItem within MyList, which would provide it access to MyList's props including updateAction.
function MyList(props) {
const { streams, actionUpdate } = props;
// Can access updateAction here
const listItem = (item,index) => {
const id = item.id
const handleUpdated = e => {
e.preventDefault();
actionUpdate(id);
};
return (
<Button
onClick={handleUpdated}
color='primary'
variant='contained'
style={{ marginTop: '0.75rem' }}
>
Update
</Button>
);
}
return (
<List>
{streams.map(listItem)};
</List>
);
}
function listView(props) {
const { classes, streams } = props;
return (
<div style={{ width: '100%' }}>
<section className={classes.content}>
<Grid container>
<Grid item style={{ width: '100%' }}>
<MyList
streams={streams}
actionUpdate={actionUpdate}
/>
</Grid>
</Grid>
</section>
</div>
);
}
const mapStateToProps = state => {
const streams = R.path(['theObject', 'arrayOfObjects'])
)(state);
return { streams };
};
const mapDispatchToProps = dispatch => {
const actionUpdate = (itemId) => {
return dispatch(theUpdateAction(itemId));
};
return { actionUpdate };
};
const MainListView = connect(
mapStateToProps,
mapDispatchToProps
)(listView);
export default withStyles(styles)(MainListView);