Closed Rando-cal closed 2 years ago
You probably don't want state to live inside this component, but rather in its parent component. For example you could have something like this for the toggle component
const Foo = props => {
const {radioValue, setRadioValue } = props
const handleChange = e => setValue(e.target.value)
const radios = [
{ name: 'one', value: 1 },
{ name: 'two', value: 2 },
]
return (
<>
<ButtonGroup>
{
radios.map((radio, idx) => (
<ToggleButton
key={ idx }
// various other props
value={ radio.value }
checked={ radio.value === radioValue }
onChange={ handleChange }
>
{ radio.name }
</ToggleButton>
)
}
</ButtonGroup>
</>
)
}
Then in any parent that renders this component, you would have something like this:
const Bar = props => {
const [radioValue, setRadioValue] = useState(1)
return (
<>
<Foo
radioValue={ radioValue }
setRadioValue={ setRadioValue }
/>
</>
)
}
the components are like: app -> home -> search -> toggle
If I need the radioValue in App, but don't want the toggle to show until Search... would that work?
Hmmmm... i suppose i don't have to render the Toggle until search, but can have the values be passed down via props....? In that case how do I pass it down without rendering it??
I believe I understand. I'm hitting a related issue where the Header component, has a conditional in it: authenticatedOptions vs unauthenticatedOptions, where the file is not seeing the radioValue, setRadioValue via the props... Its kinda defined, its just in a variable...
const unauthenticatedOptions = (
<>
<Nav.Item>
<Link to='sign-up' style={linkStyle}>Sign Up</Link>
</Nav.Item>
<Nav.Item>
<Link to='sign-in' style={linkStyle}>Sign In</Link>
</Nav.Item>
<Nav.Item>
<Searchbox
radioValue={radioValue}
setRadioValue={setRadioValue}
/>
</Nav.Item>
</>
)
const alwaysOptions = (
<>
{/* <Nav.Item>
<Link to='/' style={linkStyle}>
Home
</Link>
</Nav.Item> */}
</>
)
const Header = ({ user, radioValue, setRadioValue}) => (
<Navbar bg='primary' variant='dark' expand='md' style={navBarColor} >
<Navbar.Brand>
<Link to='/' style={linkStyle}>
StreamGenie
</Link>
</Navbar.Brand>
<Navbar.Toggle aria-controls='basic-navbar-nav' />
<Navbar.Collapse id='basic-navbar-nav'>
<Nav className='ml-auto'>
{user && (
<span className='navbar-text mr-2'>Welcome, {user.email}</span>
)}
{alwaysOptions}
{user ? authenticatedOptions : unauthenticatedOptions}
</Nav>
</Navbar.Collapse>
</Navbar>
)
export default Header
Error:
Failed to compile
src/components/shared/Header.js
Line 42:17: 'radioValue' is not defined no-undef
Line 43:20: 'setRadioValue' is not defined no-undef
Search for the keywords to learn more about each error.
This error occurred during the build time and cannot be dismissed.
Remember that in React, information flows downwards. State needs to live in the first common ancestor of all components that need to share it. That means that in your case, it sounds like it needs to live in App
, but you have to remember to pass radioValue
and setRadioValue
down to any child components that need it as props. That means that wherever you are rendering Header
, you need to pass in those values as props:
<Header
radioValue={ radioValue }
setRadioValue={ setRadioValue }
{
// whatever other props you need
}
/>
Gotcha. The values are passed into Header as props: "const Header = ({ user, radioValue, setRadioValue}) => (", but the variable unauthenticatedOptions is where it needs to be passed down again... However, since its in an ternary its not 'seeing' the variables radioValue and setRadioValue
(parent file where its passed in):
<Header user={user}
radioValue={radioValue}
setRadioValue={setRadioValue}
/>
... unless Header.js is not a component cos its not returning anything explicitly???
alwaysOptions
and authenticatedOptions
should be declared inside the component. Remember anything declared inside a function is scoped to the function. The props of your Header
component are meaningless to anything declared outside of it.
@Rando-cal was this resolved?
I think so... still testing...
Yes!!!
Resolution: Put the Toggle state vars and set method in the top App.js, then passed the two down all the way to the Toggle component via props. Had to restructure the Header.js component to use an explicit return (instead of implicit) to move all the 'jsx render ' vars inside the component.
What stack are you using?
MERN
What's the problem you're trying to solve?
I have a toggle that switches between Movie/TV for a title search. I need the toggle to be at a high level in the component hierarchy so it can be used by various other components. For instance the search bar needs to be able to check if the toggle is on Movies or TV then hit a different route for each.
Post any code you think might be relevant (one fenced block per file)
Whole radio toggle button
If you see an error message, post it here. If you don't, what unexpected behavior are you seeing?
N/A
What is your best guess as to the source of the problem?
Passing the component down without showing the toggle until its needed...
What things have you already tried to solve the problem?
I tried using the toggle a few levels down in the searchbox components and I had trouble passing a onform submit to toggle component (through props). Then also the issue of passing the toggle state back up to other components, so this is probably not correct.
Paste a link to your repository here https://github.com/Rando-cal/streamgenie-react-front