Adding tab dynamically upgradeElement - javascript

When I add a tab with react, its parent element is already upgraded. So calling upgradElement has no effect and the added tab doesn't work.
What solution, recreate all tabs with the container and upgrade it ? React just update DOM component in this case I need to dismount component ?

How about calling componentHandler.upgradeElement() or componentHandler.upgradeDom() in the componentDidUpdate phase of the specific component
componentDidUpdate() {
componentHandler.upgradeElement(this.refs.myElement);
//or componentHandler.upgradeDom('MaterialTabs');
}
EDIT 1 Tab Component
componentDidUpdate() {
componentHandler.upgradeDom();
}
newTab() {
this.setState({
newtab: 1
});
}
render() {
return (<div className="mdl-layout mdl-js-layout mdl-layout--fixed-header" key={this.state.newtab}>
<button onClick={this.newTab.bind(this)}>Add Tab</button>
<header className="mdl-layout__header">
<div className="mdl-layout__tab-bar mdl-js-ripple-effect">
<Link to="/tabtest" hash="#scroll-tab-1" className="mdl-layout__tab is-active">Tab 1</Link>
<Link to="/tabtest" hash="#scroll-tab-2" className="mdl-layout__tab">Tab 2</Link>
{ this.state.newtab ?
<Link to="/tabtest" hash="#scroll-tab-3" className="mdl-layout__tab">Tab 3</Link> : null}
</div>
</header>
<div className="mdl-layout__content">
<section className="mdl-layout__tab-panel is-active" id="scroll-tab-1">
<div className="page-content">Tab 1</div>
</section>
<section className="mdl-layout__tab-panel" id="scroll-tab-2">
<div className="page-content">Tab 2</div>
</section>
{ this.state.newtab ? <section className="mdl-layout__tab-panel" id="scroll-tab-3">
<div className="page-content">Tab 2</div>
</section> : null}
</div>
</div>);
}
I did some tests and could reproduce the problem. What helped was to put the key attribute on the root element of the tab component. When adding a new tab this key must change and react will throw away the component and rerender completly. This way all material-design-lite properties get lost and after calling upgradeDom or upgradeElement it works.
React and Material-Design-Lite
Material-Design-Lite source

From https://facebook.github.io/react/docs/component-api.html.
forceUpdate
void forceUpdate(
[function callback]
)
By default, when your component's state or props change, your component will re-render. However, if these change implicitly (eg: data deep within an object changes without changing the object itself) or if your render() method depends on some other data, you can tell React that it needs to re-run render() by calling forceUpdate().
Calling forceUpdate() will cause render() to be called on the component, skipping shouldComponentUpdate(). This will trigger the normal lifecycle methods for child components, including the shouldComponentUpdate() method of each child. React will still only update the DOM if the markup changes.
Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.

In order to highlight the most important part of Christian Steinmann's answer:
Give the surrounding .mdl-js-tabs div element the tabs count as the key attribute.
Whenever a tab is added, the key will change and React will rerender the whole tabs component. This will then the MDL upgrade.

Related

Get `children` prop from component

UPDATE:
For anyone learning and confused on this as I was, this page describes what's going on -- my confusion was between a React component vs React elements
https://reactjs.org/docs/rendering-elements.html
ORIGINAL QUESTION:
The page linked below suggests the children prop is passed by default when using FunctionComponent, however it doesn't seem to work for me. Given the following case, props.children is undefined. I'm still picking up React -- what am I doing wrong?
import React, { FunctionComponent } from "react"
type Props = {
myProp: string
}
const Nav: FunctionComponent<Props> = (props) => {
console.log(props.myProp, props.children)
return (
<main>
<nav>
FOO
BAR
</nav>
</main>
)
}
// This component is rendered from within another component, e.g. `return (<div><Nav /></div>)
My end goal is to access a child attribute somehow. The active class, for example.
source: https://fettblog.eu/typescript-react/children/
props.children === undefined because you're rendering
<div>
<Nav />
</div>
and <Nav /> has no child element in it.
If you change it to something like
<Nav myProp="Hello">
World!
</Nav>
then console.log(props.myProp, props.children) will print "Hello World!" in the console.

onClick Removing data from components

So basically I have two components. In Component 1 there is an img. In component 2 there is a button. I need when i press the button img disappears and also button disappears.
const Icons=()=> {
return (
<div className="_icons">
<div className="icons__Top">
<img src="./icons/-48.png" alt="Twitter"/>
<figcaption>Whatever</figcaption>
</div>
</div>
const Button= () => {
return (
<div className="button">
<Button variant="outlined" className="button__rightpage" >REMOVE</Button>
<caption className="text" ></caption>
</div>
)
}
There can be more than one solution,
1)I think you need to have one parent component for both components and make one state in parent component and then pass it in icon component and give it to img and default make it to false and then from button component change that state to true.
2)without parent component -> You can also use context api to change value directly from button component and hide img.

Simple button component not accepting variables

In reviewing and making my code more modular and robust, as any programmer should, I noticed I was using a similar button component multiple times. As such I decided to create a button component and just render it with the new route link and text as in the page rendered.
I'm completely new to react (~ 5 days in learning) with a fairly well versed programming background.
Simple component button, I use react-route-dom : Link prop to route to new pages.
function ActionButton () {
return (
<div className="Action">
<button className="ActionButton">
<Link to={this.props.navLink}>
{this.props.text}
</Link>
</button>
</div>
);
}
using/constructing of the button component
function ActionPage () {
return (
<div className="ActionPage">
<ActionButton
navLink="/urlLink1"
text="btn1"
/>
<ActionButton
navLink="/urlLink2"
text="btn2"
/>
</div>
);
}
this doesn't work, I get the following:
TypeError: Cannot read property 'props' of undefined
When using a stateless functional component as you are (as opposed to a class based one) the component is called with ComponentName(props) - you can access props by updating the signature of the component to:
ActionButton (props) {
Which will allow you to access props.navLink etc inside the function.
Your ActionButton component is a dump component, so you have to pass the props as a argument to the function. Update your ActionButton component as shown below.
function ActionButton (props) {
return (
<div className="Action">
<button className="ActionButton">
<Link to={props.navLink}>
{props.text}
</Link>
</button>
</div>
);}
As you are new to React, read more about dump vs smart components here: https://medium.com/#thejasonfile/dumb-components-and-smart-components-e7b33a698d43

Calling a props provided method that uses react-router properties

I'm having a hard time wrapping my head around this issue. I was wondering if someone here would be able to take a look? I have a component that I'm passing a method called this.fetchContent to as props called Filter. this.fetchContent fires an action creator that uses axios via Redux to get some data from an API, I pass it the current page location using react-router viathis.props.params.
The issue occurs with calling the method from the child component. What I've done is bound this.props.fetchContent to an onClick handler inside the Filter component. Whenever I click the <Link /> tag the function fires, and the page route gets updated. However the value of the parent components props doesn't update until after the function has fired, causing only every other click to produce the correct API call.
App:
class App extends Component {
constructor(props) {
super(props)
this.fetchContent = this.fetchContent.bind(this);
}
static contextTypes = {
router: PropTypes.object
};
componentDidMount() {
this.fetchContent();
}
fetchContent() {
let query = `${this.props.params.sub}/${this.props.params.filter}`;
this.props.fetchList(query, this.props.location.search);
}
render() {
return (
<div>
<Filter
filter={this.props.params.filter}
sub={this.props.params.sub}
search={this.props.location.search}
fetchContent={this.fetchContent} />
{React.cloneElement(this.props.children, this.props)}
</div>
);
}
}
Filter
class Filter extends Component {
render() {
return (
<div className="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
<div className="mdl-tabs__tab-bar">
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
</div>
</div>
)
}
}
I understand what's happening here but I'm not sure what the React-friendly way of solving this issue is. How can I re-factor my code to produce the results I need and what are the best practices for solving this sort of issue?
Edit: Updated the syntax but still seeing the same issue.
You have some syntax mistake I believe. You are executing the function rather than returning it.
This
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent()}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
Should be like this;
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={this.props.fetchContent}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
OR like this
<Link to={`/r/${this.props.sub}/new/${this.props.search}`} onClick={() => { this.props.fetchContent() }}>
<span className="mdl-tabs__tab is-active">Hot</span>
</Link>
PS: I believe you have a typo on App component since you don have a closing on Filter component at render.

How do I use a custom DOM node to render to from within a react component

I have the following problem:
I want to write jsx code like
<div className="my-section">
<Window>
<div>Window content</div>
</Window>
</div>
<div className="window-container">
</div>
somewhere in my react content, but I want the window to render in a special DOM element with other windows, something like
<div class="my-section"></div>
<div class="window-container">
<div class="window">
<div>Window Content</div>
</div>
</div>
And to do this transparently I need to tell the component to render to a special DOM node from within the component. Is there a way to do this? If not, how should I accomplish the functionality I am looking for from within React?
You're looking for the special this.props.children list.
When you create a React component instance, you can include additional React components or JavaScript expressions between the opening and closing tags like this:
<Parent><Child /></Parent>
Parent can read its children by accessing the special this.props.children prop.
This will allow you to get the children defined inside your element, then insert them at an arbitrary point for render.
render() {
return (
<div className="window container">
<div className="window">{this.props.children}</div>
<div className="window"></div>
...
</div>
);
}

Categories

Resources