How to change tab from parent in react material Tabs - reactjs

I've got a component like FeedSwitcher with two tabs inside
one for the general feed the other one only for the posts of the current user
in FeedSwitcher component at the start the value is 0 therefore
the current user can view all the feed.
const FeedSwitcher = ({feed, posts, user }: FeedSwitcherProps) => {
const classes = useStyles();
const [value, setValue] = useState(0);
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<Tabs
value={value}
onChange={handleChange}
variant="fullWidth"
indicatorColor="primary"
textColor="primary"
aria-label="switcher tabs"
>
<Tab icon={<PeopleIcon />} aria-label="phone" />
<Tab icon={<PersonIcon />} aria-label="favorite" />
</Tabs>
<TabPanel value={value} index={0}>
<Feed feed={feed} />
</TabPanel>
<TabPanel value={value} index={1}>
<Posts posts={posts} user={user} />
</TabPanel>
</div>
);
};
After the current user post a new thread
(the form is in the parent component)
I want to show the tab with index 1
How can set the value from the parent?
Should I use a redux state or is there
an other direct and simpler way?

The state needs to be in the parent component.
You can feed the child component with the value, and pass it a function argument like onValueChange that it can use to trigger an update on the parent's state.
// in parent
const [feedSwitcherValue, setFeedSwitcherValue] = useState(0);
return (
<FeedSwitcher
feed={feed}
posts={posts}
user={user}
value={feedSwitcherValue}
onValueChange={value => setFeedSwitcherValue(value)}
/>
);
// child
const FeedSwitcher = ({feed, posts, user, value, onValueChange }: FeedSwitcherProps) => {
const classes = useStyles();
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
onValueChange(newValue);
};
return (
<div className={classes.root}>
<Tabs
value={value}
onChange={handleChange}
variant="fullWidth"
indicatorColor="primary"
textColor="primary"
aria-label="switcher tabs"
>
<Tab icon={<PeopleIcon />} aria-label="phone" />
<Tab icon={<PersonIcon />} aria-label="favorite" />
</Tabs>
<TabPanel value={value} index={0}>
<Feed feed={feed} />
</TabPanel>
<TabPanel value={value} index={1}>
<Posts posts={posts} user={user} />
</TabPanel>
</div>
);
};

Related

Get Child components constants/state in parent component in React

I have a component which is a MUI TAB like this
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
value={value}
onChange={handleChange}
aria-label="basic tabs example"
>
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
<Child1 />
</TabPanel>
<TabPanel value={value} index={1}>
<Child2 />
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
<Box>
<Button onClick={submittab}>Submit</Button>
</Box>
</Box>
As mentioned, there are 2 child components with some textfields in it.
What I am trying to achieve is to read the child data in parent and submit it to an API as a single object.
Please help
Below the Sandbox
https://codesandbox.io/s/naughty-shadow-u2icz1?file=/demo.tsx:1233-1962
Please note I am working in typescript
Here is my child component1
import { FormLabel, TextField } from "#mui/material";
import react, { useState } from "react";
function Child1() {
const clientObj = {
user: {
name: "",
age: ""
}
};
const [client, setClient] = useState(clientObj);
const handlechange = (event: { target: { name: any; value: any } }) => {
const { name, value } = event.target;
setClient((prevState) => ({
...prevState,
context: {
...prevState.user,
[name]: value
}
}));
};
return (
<>
<FormLabel>Name</FormLabel>
<TextField
name="name"
id="text-id"
value={client.user.name}
onChange={handlechange}
/>
<FormLabel>Age</FormLabel>
<TextField
name="name"
id="text-id"
value={client.user.name}
onChange={handlechange}
/>
</>
);
}
export default Child1;
You could use a state in your parent component that will be passed as props to your children, so that they can use the parent's update state function.
Parent code:
const [state, setState] = useState()
<Child parentState={{state, setState}} />
Children code:
export function Child({parentState}) {
const {parentStateValue, setParentState} = parentState
const childTitle = 'Acme'
return <button onClick={setParentState(e => {...e, childTitle })} >childTitle</button>
}
the ideal would be to provide keys to your children so that you can manage each of their data independently in the state.

How to pass a value from reactjs app to another reactjs app?

I have to 2 Reactjs App, I need to pass a value from my App1 to App2 using link, but I dont know how, please help me thanks.
const location = useLocation();
const tab = getUrlParameter(location.search, 'tab');
with this I am now successfully getting the data in my App1 , lets says that data is (2), the problem is when i tried to click the other tab, it doesnt work now, why?
App1
<u>View Student</u> // I need to pass a value to App2, the value i need to pass is
App2 / receive value from App1
export default function BasicTabs() {
const location = useLocation();
const tab = getUrlParameter(location.search, 'tab'); // with this I am now successfully getting the data in my App1 , lets says that data is (2)
const [value, setValue] = React.useState(0);
useEffect(() => {
if(tab !== 2 ? tab : value){
console.log(tab)
setValue(2)
}else{
setValue(0)
}
})
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<Box sx={{ width: '100%' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</Box>
);
}
One option is to use query string parameters. So you would do something like
https://App2Url/student/4?App1Key=App1Value

ReactJS Material UI disable other tabs on button click [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 19 days ago.
Improve this question
Have similar code with action for a Button component click in each tab
https://codesandbox.io/embed/cbn97?codemirror=1
How can I disable other tabs on Button click in current tab?
How can I pass a "disabled" property to already displayed, rendered tab component, update it?
New to ReactJS
Since you've indicated in the comments that the current page may also be disabled I suggest you do something like this:
export default function SimpleTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [isLoading, setIsLoading] = React.useState(false)
const handleOperation = () => {
setIsLoading(true)
// Do some synchronous operation that takes time
setIsLoading(false)
}
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" {...a11yProps(0)} disabled={isLoading}/>
<Tab label="Item Two" {...a11yProps(1)} disabled={isLoading}/>
<Tab label="Item Three" {...a11yProps(2)} disabled={isLoading}/>
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<button onClick={handleOperation}>start operation</button>
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</div>
);
}
So the approach above is to create an isLoading state that identifies whether one of your tab button operations is in progress. Inside your tab button handler function(s) set isLoading to true making the tabs disabled and set isLoading to false after the operation is done.
Just put result of functions with conditions to disabled prop of your tabs:
export default function SimpleTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [operationDone, setOperationDone] = React.useState(false)
const handleChange = (event, newValue) => {
setValue(newValue);
};
const isDisabled = (tabIndex) => {
if(operationDone) {
return false;
}
else {
if(value !== tabIndex) {
return true;
}
return false;
}
}
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" disabled={isDisabled(0)} {...a11yProps(0)} />
<Tab label="Item Two" disabled={isDisabled(1)} {...a11yProps(1)} />
<Tab label="Item Three" disabled={isDisabled(2)} {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<button onClick={() => setOperationDone(true)}>change operation done</button>
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</div>
);
}

Why Active Tab Redirecting to First Tab in React Material

I have successfully redirect the tab depending on the routes. My problem is when I'm on the second and succeeding tabs, when i refresh the browser, the active highlight on the tabs is going back the first tab?
Why is this happening? Pls check my code below
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`scrollable-auto-tabpanel-${index}`}
aria-labelledby={`scrollable-auto-tab-${index}`}
{...other}
>
{value === index && (
<Box pt={4}>
<div>{children}</div>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
function a11yProps(index) {
return {
id: `scrollable-auto-tab-${index}`,
'aria-controls': `scrollable-auto-tabpanel-${index}`,
};
}
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
maxWidth: 640,
},
}));
export default function Settings() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div>
<AppBar position="static" color="inherit" className={classes.root}>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
>
<Tab label="Users" component={Link} to="/users" {...a11yProps(0)} />
<Tab label="Products" component={Link} to="/products" {...a11yProps(1)} />
<Tab label="Sales" component={Link} to="/sales" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
<Users />
</TabPanel>
<TabPanel value={value} index={1}>
<Products />
</TabPanel>
<TabPanel value={value} index={2}>
<Sales />
</TabPanel>
</div>
);
So, you want to render same component at different routes
<BrowserRouter>
<Route path={"/"} exact component={TabComponent} />
<Route path={"/users"} exact component={TabComponent} />
<Route path={"/products"} exact component={TabComponent} />
<Route path={"/sales"} exact component={TabComponent} />
</BrowserRouter>
and you want to keep active tab depending on route path, you can achieve this by checking pathname in useEffect.
useEffect(() => {
const pathname = props.history.location.pathname;
switch (pathname) {
default:
setValue(0);
break;
case "/users":
setValue(0);
break;
case "/products":
setValue(1);
break;
case "/sales":
setValue(2);
break;
}
}, [props.history.location.pathname]);
Here working example: https://codesandbox.io/s/floral-rgb-6o55s?fontsize=14&hidenavigation=1&theme=dark

How to show contents inside a tab?

I am trying to create a form with three tabs.Now the tabs are created and i am able to switch between them but can not figure out how to display contents inside a tab
I have tried writing markup tags like h1 in between but nothing is shown on the output.
export class Stackreact extends Component {
constructor(props) {
super(props);
this.state = { value: '1' }
}
handle_change = (value) => {
this.setState({ value })
}
render() {
return (
<div>
<Tabs value={this.state.value} onChange={(e, v) => { this.handle_change(v) }} indicatorColor="primary"
textColor="primary" centered>
<Tab value='1' label='BASIC DETAILS'><h1>First Tab</h1></Tab>
<Tab value='2' label='CONTACT DETAILS'><h1>Second Tab</h1></Tab>
<Tab value='3' label='MORE DETAILS'><h1>Third tab</h1></Tab>
</Tabs>
</div>
)
}
}
I want the contents of h1 tags to be displayed in their respective tabs. Please help.Also i am new to this language.
After working a lot I have come up with this solution which is working fine.
render() {
let content_array = [<h1>First Tab</h1>, <h1>Second Tab</h1>, <h1>Third Tab</h1>];
return (
<div>
<Tabs value={this.state.value} onChange={(e, v) => { this.handle_change(v) }} indicatorColor="primary"
textColor="primary" centered>
<Tab value='1' label='BASIC DETAILS'></Tab>
<Tab value='2' label='CONTACT DETAILS'></Tab>
<Tab value='3' label='MORE DETAILS'></Tab>
</Tabs>
<Paper>
{content_array[this.state.value - 1]}
</Paper>
</div>
)
}
You can try using TabView and TabPanel from primereact
<TabView>
<TabPanel>
<h1>First Tab</h1>
<TabPanel />
<TabPanel>
<h1>Second Tab</h1>
<TabPanel />
<TabView />
You can research on your own on the props accepted by TabView and TabPanel
you can use components like this:
<div className={classes.root}>
<AppBar position="static">
<Tabs value={value} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</AppBar>
<TabPanel value={value} index={0}>
Item One
</TabPanel>
<TabPanel value={value} index={1}>
Item Two
</TabPanel>
<TabPanel value={value} index={2}>
Item Three
</TabPanel>
</div>
official link : Tabs
You are trying to see the content but you've defined it in the wrong place, here you have an example of how to use Tabs and Tab, because you need to define the data that you want inside of each Tab outside the Tabs component (Tab in meant to be used as a self-closing tag).
Here is the simplest answer using hooks inspired by the accepted answer.
import { useState } from 'react';
..
const [tabState, setTabState] = useState(1);
...
const handleTabs = (value) => {
setTabState(value);
return;
}
let tabs_array = [<>{variable_with_contents_tab_1}</>, <>{tab_2_contents}</>];
Then in the render, you can provide the tab ui
<Paper className={classes.root}>
<Tabs
value={tabState}
onChange={(event, value) => { handleTabs(value) }}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab value={1} label='Tab1'>
</Tab>
<Tab value={2} label="Tab2" />
</Tabs>
</Paper>
<Paper>
{tabs_array[tabState-1]}
</Paper>

Resources