I made a test where I do React.render() in a child component and pass a prop to it. The app structure looks like:
<App>
<Child />
</App>
Then in <Child />, I render <Outside /> component with another React.render(). When I checked in Chrome React firebug, the App structure is:
<App>
<Child />
</App>
<Outside />
instead of:
<App>
<Child />
<Outside />
</App>
However, when passing a {selected : true } state from <App />, it displays well as a prop in <Outside />, but when I make a state change to { selected : false } in <App />, both <Child /> and <Outside /> don't receive the updated prop. I think it happens because <Outside /> is out of the <App /> scope so the data flow doesn't flow well. (Sorry for my English)
You can check the test here: http://jsbin.com/yazaqo/1/edit?js,console,output
What I'm trying to ask is: Is there any other way to update a component which is outside the App scope?
The Child component is receiving the updated prop, its just not being logged to the console.
Only render and componentWillReceiveProps are invoked when a component receives new props, so if you move the console.log to either one of those methods, you'll see the updated value.
This is also why Outside is not receiving the updated prop. You're rendering it in componentDidMount, which is only invoked once, when the component is mounted.
It should be rendered in Child's render method the same way Child is rendered in the App component. The other option would be to render it in componentWillReceiveProps, although you may run into some problems doing it that way.
Hope this helps.
Related
I have a ReactJS application. The <App /> component is wrapped with a <ContextProvider /> component, because I need to have its state shared among components that only have <App /> as a common ancestor, since it is the <App /> component that mounts the 3 React Router v5 <Switch /> that are responsible of rendering:
the Header
the Body
the Right column
To wrap up:
<ContextProvider value={myValue}>
<App {...props} />
</ContextProvider>
Everything is working nice and smoothly, but I have a doubt. The <Header /> component of a section that consumes the <ContextProvider /> above is defined and exported in this way:
import React from 'react';
import { useHistory } from 'react-router-dom';
// Other imports
function Header() {
const history = useHistory();
const goToHomePage = () => { history.push(PATHS.HOME_PAGE); };
// Some business logic
console.debug('render');
return (
<HeaderComponent
title={(
<TitleComponent title="My header" />
)}
/>
);
}
export default React.memo(Header);
If I inspect the console I can see that every time the values within <ContextProvider /> change, the render string is printed out, meaning that the <Header /> component is re-rendering.
But this component has no props and is exported via React.memo, so I don't understand why it is continuously re-rendering.
This is app.js
As result I just see a white page. I don't see any errors or anything.
The Route component API's element prop takes a ReactNode, a.k.a. JSX. Buy should be rendered as JSX, not passed as a reference to the component.
Example:
<Route path="/" element={<Buy />} />
How can I specify that a component should be rendered absolutely before any other component?
I want to specify that <Footer /> and all the child components of footer should be rendered before any other components.
The reason I want this is because I have code that depends on the html that footer is rendering which means that the reference to <Footer /> is undefined in the other components if <Footer /> doesn't render first.
Here's an example:
export default class Layout extends React.Component {
...
render(){
return (
<Body />
<Footer /> //Render first
);
}
}
The only way I see for you do do that is:
Have the information about the render status for the footer in a state. (Let's assume your name it isFooterRendered and it is a boolean)
You set isFooterRendered to be false in the initial state.
You only render the children components when isFooterRendered is true
In componentDidMount you will have a reference to Footer, set isFooterRendered to be true.
(Some people claim that it's bad to setState on componentDidMount but in your case looks like a legit use case, aside from that React Docs expose a similar example)
For example, I made a slider component in React that takes child components to make a category slider.
So, it is something like:
<Slider>
<Child someProps={this.props.someProps1} />
<Child someProps={this.props.someProps2} />
<Child someProps={this.props.someProps3} />
<Child someProps={this.props.someProps4} />
</Slider>
Is something like this possible in angular 1.5? I'm having a lot of trouble understanding angular components and it is not really ticking with me the way React does.
Thanks.
I have the following structure in my root component
<div className={styles.main_container}>
<Provider store={store}>
<Topbar></Topbar>
</Provider>
<div className={styles.scene_and_tools}>
<Provider store={store}>
<Sidebar></Sidebar>
</Provider>
<Provider store={store}>
<Scene></Scene>
</Provider>
</div>
<Provider store={store}>
<Timeline></Timeline>
</Provider>
</div>
This works fine but I find it a bit not so "DRY" to repeat <Provider> for every single component that I want to pass context. So I tried
<div className={styles.main_container}>
<Provider store={store}>
<Topbar></Topbar>
<div className={styles.scene_and_tools}>
<Sidebar></Sidebar>
<Scene></Scene>
</div>
<Timeline></Timeline>
</Provider>
</div>
But I am getting the following error:
Failed propType: Invalid prop `children` supplied to `Provider`,
expected a single ReactElement. Check the render method of `App`.
Is there a way to make my code more DRY or I have to live with this redundancy?
The first variation is completely redundant. The only reason Provider exists in the first place is so that you can avoid passing the store down and explicitly. Otherwise you could just as well remove it and pass store as a prop to container components themselves.
The intended use case for Provider is to wrap the rootmost component. All children and grandchildren will then receive the store implicitly. You should only do it once, and put a single React element inside. Your second example does not work because you put three elements inside it: Topbar, div and Timeline. Wrap the outer div instead and it will work. Better yet, move Provider to the place where you call ReactDOM.render() and wrap your rootmost App component in it. Then you don't need it anywhere else.