I understand that the purpose of layouts is that it should be shared across all the pages. But there needs to be a way to send customisations from a page itself to the layout so you can do things like highlight certain elements in the header for example.
At the moment the only way is to embed the page variations into the layout itself and check the location.pathname
which really isn't appropriate.
You could pass a prop to the pages that you could call from them e.g.
render () {
return <div>
{ this.props.children({...this.props, updateLayoutFunction }) }
</div>
}
You'd then update the layout state and re-render.
Whilst that does work it definitely isn't clean... and close to an anti-pattern...
Layout components are the parents to page components so not sure why you think pages should pass props to layouts.
I'm attempting multilingual support, so being able to pass certain pieces such as the different translations would be very helpful.
I am also interested to pass a context to layouts, I would pass it from gatsby-node.js
though. It is useful for multilingual website: you pass the language, so you can query the appropriate strings in the layout with graphql.
We could use multiple layouts files like here: https://github.com/gatsbyjs/gatsby/pull/1895
But it would be more simple passing a simple context to it.
Is it possible to do that @KyleAMathews ?
yeah, when you pass context when you create a layout https://www.gatsbyjs.org/docs/bound-action-creators/#createLayout
Thanks Kyle, that will help a lot.
On Sep 23, 2017 10:08, "natural data corruption" notifications@github.com
wrote:
How can I pass a method as a prop from a layout to this.props.children ?
I named my method updateLayoutFunction but
{ this.props.children({...this.props, updateLayoutFunction }) }
returns "ReferenceError: updateLayoutFunction is not defined."—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/gatsbyjs/gatsby/issues/2112#issuecomment-331618836,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AH_TYXMR4P-ghsLYWRtOx29Wsq1QsmDVks5slLx2gaJpZM4PXbM_
.
@KyleAMathews at that point, is it aware of the path though? I take it probably not?
Which point? When creating a layout? No — you'd need to pass it data keyed by path.
Easier probably to use the "parent passes a callback function to child" pattern though.
@KyleAMathews yea i assumed so. We've already began to work towards that approach.
@KyleAMathews @davidhouweling I have a header component in the layout, and when clicked on the labels on the header inside the layout, I want the page to scroll, for this, I need to pass some data to the header component inside the layout. Please guide me through it. Thanks.
I'm trying to pass props to children like this:
render () {
return
however, I get the error that updateLayoutFunction is not defined, no matter where and how I try to define it. Could you please tell me how can it be defined?
assuming updateLayoutFunction is a method of parent component, you can do something like this:
render() {
const updateLayoutFunction = this.updateLayoutFunction
...
{ this.props.children({...this.props, updateLayoutFunction }) }
}
Thanks, man. You saved my life.
One thing to keep in mind with the approach, it only appears to render the update to the layout on the client side. It does not put it into the statically generated html file. As a result I moved away from using the layout solution all together. We ended up creating a component which is applied via the page template as a root component of the template.
Thank you for the information. I didn't test it on the statically generated site. It seems that I will have to move away from the layout solution too.
I have a state variable on the template component which is passed as props to the template children, however when the state is updated, the props that is passed to the children does not update? Is this a bug? The only way I could get this to work is by setting the state variable as a key property on the template component, so when it changes it forces react to unmount and and mount the template again updating the props that is passed to the children. Anyone else got a solution for this?
@davidhouweling can you share your solution?
I need to pass the state from index.js to submit.js. The state contains a user input which is an ID required to make an API call in the submit.js. How do I pass the state from index.js to submit.js?
<Link to="/submit" params={{value: this.state.value}} onClick={this.handleSubmit}> Submit </Link>
import submit from './submit.js'
...
handleClick = () => {
const {value} = this.state
submit(value)
}
...
<button onClick={handleClick}>Submit</button>
I think you should add layout: false
render () {
return <div>
{ this.props.children({...this.props, layout: false, updateLayoutFunction }) }
</div>
}
/layouts/index.js
lacks the functionailty required by the OP. Which is likely a valid use-case.
In order to make this work, component composition can be implemented as an alternative solution.
1)Create a layout at /components/layout.js
with the component:
export default ({aPageProp, children}) => (
<div>
{aPageProp}
header
{children}
footer
</div>
);
2)Create a page at /pages/page.js
with the component:
export default () => (
<Layout aPageProp="value">
Page content
</Layout>
);
Anyone has a solution ?
I would to pass variables to layout for https://moz.com/learn/seo/hreflang-tag
Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!
I had a similar issue where I moved my base component <Application>
which was doing some basic setup like meta tags, global styles, top navigation with theme switching, setting the title etc
This was easy to render as the root component of my various page layouts and pass whatever props I wanted into it (like page title) but then it became apparent than when switching routes everything was being unmounted and re-rendered, causing the state in Application
to be lost (e.g. the currently chosen theme).
There is a section: https://www.gatsbyjs.org/docs/layout-components/#how-to-prevent-layout-components-from-unmounting
But it gives a solution without mentioning how to communicate between this component and the rest of the app. The element
that is passed in here is not a function it's a ReactElement and so I can't pass in props from Application
to it with "render props" as suggested.
I've ended up doing this but not sure if I haven't understood Gatsby properly as it feels like a hacky solution to something that everyone must come across when making an app:
export const wrapPageElement = ({ element, props }) => {
return (
<Application {...props}>
{(state, dispatcher) =>
React.Children.map(element, child => React.cloneElement(child, { state, dispatcher }))
}
</Application>
);
};
Maybe a better solution will be to move the state
and dispatcher
to a Context if this is really the way to do it.
Most helpful comment
You could pass a prop to the pages that you could call from them e.g.
You'd then update the layout state and re-render.