Passing data from child to parent component / React hooks - javascript

Can someone tell me if there is a way to pass the dark variable from Navbar component to the App component here is a little part from my Navbar component which contains the state:
function Navbar({search, handleSearch, region, handleChange, number}){
const [dark , setDark] = useState(false)
function handlThem(){
setDark(prevThem=> !prevThem )
}
return(
<div className="navbar" style={ dark ? {backgroundColor : "#333"} : null}>
)
}
I want to pass dark here in the App component to change and use it to change it's class or toggle to change the background like this style={ dark ? {backgroundColor : "#333"}
the App component :
function App() {
return (
<div className="App">
<Body />
</div>
);
}

This is a good use case for React Context. I'm providing an example using hooks API. You can create a context then use the values (state and state setter) in any of the components you wrap with the provider.
const ThemeContext = React.createContext();
function App() {
const [dark , setDark] = React.useState(false);
return (
<ThemeContext.Provider value={{ dark, setDark }}>
<Body />
</ThemeContext.Provider>
);
}
function Navbar() {
const value = React.useContext(ThemeContext);
return (
<div>Navbar<button onClick={() => value.setDark(true)}>Change to Dark</button></div>
);
}
function Body() {
const value = React.useContext(ThemeContext);
return (
<div style={ value.dark ? {backgroundColor : "#333"} : null}>
<Navbar />
<div>Rest of the body</div>
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root" />

Try this
App.js
function App() {
function getTheme(themeValue) {
console.log(themeValue);
}
return (
<div className="App">
<Body getTheme={getTheme}/>
</div>
);
}
Navbar.js
function Navbar({search, handleSearch, region, handleChange, number, getTheme}){
const [dark , setDark] = useState(false)
function handlThem(){
const theme = !dart;
setDark(prevThem=> theme )
getTheme(theme);
}
return(
<div className="navbar" style={ dark ? {backgroundColor : "#333"} : null}>
)
}
As I passed to body, you pass to Navbar component, you didn't post body component that's why passed to body component and accessed in Navbar. you can change as per your requirement.

Related

MUI theme light/dark switch in header(AppBar)

I'm trying to find a way to switch between dark and light theme in my web app.
I want to add the switch in my AppBar component which is inside my header but I'm not sure how to get it to work on all of the web app and not just the header.
AppBar.js :
//imports ...
const AppBar = () =>{
const [theme, setTheme] = useState(false);
const changeTheme = () => {
setTheme(!theme);
};
//rest of the code....
<Box sx={{ flexGrow: 0 }}>
<Switch checked={theme} onChange={changeTheme} />
</Box>
};
export default AppBar;
here is the code from the Header.js
const Header = () => {
return (
<header>
<AppBar />
</header>
);
};
export default Header;
so the header is just rendering one component one could get rid of it if it was necessary.
and here is my App.js (routes)
//imports ...
//themes ...
const app = ()=>{
return (
<React.Fragment>
<ThemeProvider theme={theme ? lightTheme : darkTheme}>
<CssBaseline />
<Router>
<Header />
<Routes>
//Routes ...
</Routes>
<Footer />
</Router>
</ThemeProvider>
</React.Fragment>
);
}
export default App;
I'd really appreciate the help and Thanks in advance!
you can store the value of theme inside context or redux store and change it using a dispatch function once that value changes the whole component related to it will re render !, so your component will change the value inside context ! rather than having the value stuck inside one component.

Add different navbar on different pages with layout.js next js

I've two navbar layout and ten pages in my next js project. Now I need to set navbar one for five pages and navbar two for rest of the pages with layout.js at once. How can I do this. If anyone help me about this, I'll be very thankful. Thanks in advance.
NavbarOne.js
const NavbarOne = () => {
return (
<div>
<h1>Navbar One</h1>
</div>
);
}
export default NavbarOne;
NavbarTwo.js
const NavbarTwo = () => {
return (
<div>
<h1>Navbar Two</h1>
</div>
);
}
export default NavbarTwo;
Layout.js
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
const Layout = ({ children }) => {
return (
<div>
<NavbarOne />
{/* <NavbarTwo /> */}
{children}
<Footer />
</div>
);
}
export default Layout;
_app.js
import Layout from '../components/layout/Layout';
import '../styles/styles.scss'
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp
Updated
Layout.js
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
import NavbarTwo from "../Navbar/NavbarTwo";
const Layout = ({ children, criteria}) => {
return (
<div>
{ criteria ?
<NavbarOne />
:
<NavbarTwo />
}
{children}
<Footer />
</div>
);
}
export default Layout;
__app.js
import Layout from '../components/layout/Layout';
import '../styles/styles.scss'
function MyApp({ Component, pageProps }) {
return (
<Layout criteria={true}>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp
__admission.js
import Layout from "../components/layout/Layout";
const admission = () => {
return (
<Layout criteria={false}>
<div>
<h1>Admission</h1>
</div>
</Layout>
);
}
export default admission;
You can do something like
const Layout = ({ children, criteria }) => {
return (
<div>
{ criteria ? //ternary operator
<NavbarOne />
:
<NavbarTwo />
}
{children}
<Footer />
</div>
);
}
export default Layout;
And pass a boolean to your Layout as criteria to choose between Navbars
const Page1 = () => {
return (
<Layout criteria={true}> // will display navbar 1
<p>Im page 1</p>
</Layout>
);
}
export default Layout;
const Page2 = () => {
return (
<Layout criteria={false}> // will display navbar 2
<p>Im page 2</p>
</Layout>
);
}
export default Layout;
With three navbars you can do
const Layout = ({ children, navbarType }) => {
return (
<div>
{ navbarType == 1 && <NavbarOne />}
{ navbarType == 2 && <NavbarTwo />}
{ navbarType == 3 && <NavbarThree />}
{children}
<Footer />
</div>
);
}
export default Layout;
And pass a number to your Layout as navbarType to choose between Navbars
const Page1 = () => {
return (
<Layout navbarType={1}> // will display navbar 1
<p>Im page 1</p>
</Layout>
);
}
export default Layout;
const Page2 = () => {
return (
<Layout navbarType={2}> // will display navbar 2
<p>Im page 2</p>
</Layout>
);
}
export default Layout;
const Page3 = () => {
return (
<Layout navbarType={3}> // will display navbar 3
<p>Im page 3</p>
</Layout>
);
}
export default Layout;
If you prefer an option where, you want to add N number of navbars.
and select them by some index number.
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
const Layout = ({ children, index }) => {
const navBarList = [<NavbarOne />, <NavbarTwo />];
const renderNavBar = (_index) => navBarList[_index];
return (
<div>
{renderNavBar(index)}
{children}
<Footer />
</div>
);
}
export default Layout;
In your where you calling your app, you should be calling it as such.
import Layout from './components/layout.js';
export default function Home() {
return (
<div>
<Layout index={1}>
<p>byebye</p>
</Layout>
</div>
);
}
You can pass a props called navbar to the Layout Component like this:
export default function PageOne() {
return (
<Layout navbar="one">
<div className="container">
<h1>Page One</h1>
</div>
</Layout>
)
}
export default function PageTwo() {
return (
<Layout navbar="two">
<div className="container">
<h1>Page Two</h1>
</div>
</Layout>
)
}
And later render the Navbar Components conditionally like this:
const Layout = ({ children, navbar }) => {
return (
<div>
{ navbar === 'one' && <NavbarOne />}
{ navbar === 'two' && <NavbarTwo />}
{children}
<Footer />
</div>
);
}

how to change child component state in reactjs

I came across the following problem: I need to use another component's function inside a component:
header.js
export default function Header() {
const [showModalLogin ,setShowModalLogin] = useState(false);
return(
<>
<span>Hi, <Link onClick={() =>{ setShowModalLogin(true)}}>login</Link> </span>
{showModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
home.js
import Header from '../../components/header/header';
export default function Home() {
return (
<>
<Header />
<Link onClick={() =>{ setShowModalLogin(true)}}>open login</Link>
</>
}
How do I do in home.js to call the setShowModalLogin function that is in header.js ? I'm trying to use the context api too, but I still can't solve it.
You can just place useState in Header component and pass setShowModalLogin as props:
import Header from '../../components/header/header';
export default function Home() {
const [isShowModalLogin ,setShowModalLogin] = useState(false);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}
export default function Header({ isShowModalLogin, setShowModalLogin }) {
return(
<>
<span>Hi, <Link onClick={() => setShowModalLogin(true)}>login</Link> </span>
{isShowModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
Then you can do it in this way:
Create Context
Save useState inside
Use it everywhere you need
export const YourContext = createContext();
export const YourProvider = ({ children }) => {
const [isShowModalLogin, setShowModalLogin] = useState(false);
const value = {
isShowModalLogin,
setShowModalLogin
};
return <YourContext.Provider value={value}>{children}</YourContext.Provider>;
}
// App.js
const App = () => {
return (
<YourProvider>
<AppContent />
</YourProvider>
)
}
So now you can use it like here:
import Header from '../../components/header/header';
export default function Home() {
const { isShowModalLogin, setShowModalLogin } = useContext(YourContext);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}

how do you pass down an object containing props

after getting all mixed up with state, i am now trying to restructure my app in a way that might be more reflective of best practices (not sure if this is the way, advice is welcome.)
so, i have my main page, which holds 3 states: viewer,buyside,sellside
there are also three different components, one for each of those states.
i want to be able to pass the props down from the main page, through those components, to their children (i've read this is the best approach??)
main page:
//we have 3 states for the website: viewer,buyside customer, sellside customer
const [visitorType, setVisitorType] = useState('viewer');
if (visitorType == 'viewer') {
return(
<div>
<Viewer visitortype='viewer' setvisitor={()=>setVisitorType()}/>
</div>
)}
else if (visitorType =='buyside') {
return(
<div>
<Buyside visitortype='buyside' setvisitor={()=>setVisitorType()}/>
</div>
)}
else if (visitorType =='sellside') {
return(
<div>
<Sellside visitortype='sellside' setvisitor={()=>setVisitorType()}/>
</div>
)}
};
what is the best way to pass down the main page props, so that i can bring them down to any grandchildren, along with the child props?
the viewer component -UPDATED-:
const MainView = (props) => {
return(
<>
<Navbar mainprops={{props}}/>
</>
)
};
export default MainView
i was previously just passing them individually, but realized it might be better to do so as one object...
UPDATE: point taken on the syntax, but i'm wondering how i can best pass the objects
nav component (grandchild)
const Navbar = (props) => {
const {mainprops} = props.mainprops;
if (mainprops.visitortype == 'viewer') {
return(
<>
<h1>viewer navbar</h1>
</>
)}
else if (mainprops.visitortype =='buyside') {
return(
<>
<h1>buyside navbar</h1>
</>
)}
else if (mainprops.visitortype =='sellside') {
return(
<>
<h1>sellside navbar</h1>
</>
)}
};
export default Navbar;
UPDATE 2 - this works, but not sure if it is the correct way, are these still considered object literals??
viewer component:
const MainView = (props) => {
const mainprops = {...props}
return(
<>
<Navbar mainprops={mainprops}/>
</>
)
};
export default MainView
navbar component
const Navbar = (props) => {
const mainprops = {...props.mainprops};
if (mainprops.visitortype == 'viewer') {
return(
<>
<h1>viewer navbar</h1>
</>
)}
else if (mainprops.visitortype =='buyside') {
return(
<>
<h1>buyside navbar</h1>
</>
)}
else if (mainprops.visitortype =='sellside') {
return(
<>
<h1>sellside navbar</h1>
</>
)}
};
export default Navbar;
if this is correct, then is this what #amir meant?
First there are certain rules for passing props:
You never ever pass literal object as props since it will not be the same every re-render and will cause the child component to re-render too (without any new info)
You don't need to do that
<Viewer visitortype='viewer' setvisitor={()=>setVisitorType()}/>
You can:
<Viewer visitortype='viewer' setvisitor={setVisitorType}/>
since it comes from useState react make sure the setVisitorType keeps the same reference
And now for you error, you almost correct you just did a js syntax error
you should write it like this:
const MainView = (props) => {
return(
<>
<Navbar mainobj={{
visitortype:props.visitortype,
setvisitor:props.setvisitor
}}
/>
</>
)
};
export default MainView
But again you never send literal object as props
I would keep it inside a ref or state (depend if the visitor state will be change)

setState is not defined with reactJS

I'm working with reactJS and I am trying to use setState so that i can use that state to determine which way the graph needs to rotate but I get an error saying 'setState' is not defined no-undef. Do I need to have a constructor to initialize the state?
Code:
class App extends React.Component {
render() {
const {rotate, setRotate} = setState(false)
return (
<div className="custom-container">
<Tree
data={data}
height={600}
width={1000}
svgProps={{transform: 'rotate(${rotate ? "90" : "0")'}}
/>
<button onClick={() => setRotate(!rotate)}>Rotate</button>
</div>
);
}
}
If you are trying to use, "useState" instead of setState,
'useState' is used for having a state in functional components, you will have to convert class component to function component as below and then use 'useState'
export default function App() {
const [rotate, setRotate] = React.useState(false)
return (
<div className="custom-container">
<Tree
data={data}
height={600}
width={1000}
svgProps={{transform: 'rotate(${rotate ? "90" : "0")'}}
/>
<button onClick={() => setRotate(!rotate)}>Rotate</button>
</div>
);
}
You could also try this:
class App extends React.Component {
state = {
rotate: false
};
render() {
return (
<div className="custom-container">
<Tree
data={data}
height={600}
width={1000}
svgProps={{transform: 'rotate(${rotate ? "90" : "0")'}}
/>
<button onClick={() => this.setState({ rotate: !this.state.rotate})}>Rotate</button>
</div>
);
}
}
I think you are trying to use useState();
Make sure you import useState at the top first and also use function component instead of the class component :
import React, {useState} from 'react';
function App() {
const [rotate, setRotate] = useState(false)
return (
<div className="custom-container">
<Tree
data={data}
height={600}
width={1000}
svgProps={{transform: 'rotate(${rotate ? "90" : "0")'}}
/>
<button onClick={() => setRotate(!rotate)}>Rotate</button>
</div>
);

Categories

Resources