I'm pretty new to React and Redux so I may be doing this completely the wrong way, in fact judging from a few other answers to similar questions on here I suspect I'm doing quite a lot wrong.
I've got a button in my 'Layout' component which adds a class to a div, this class comes from a state. The button is a toggle and will turn the state & class on and off (this will result in making a menu appear and dimming the rest of the page).
However I also want any interaction with the 'Nav' component (which lives inside a 'Header' component which in turn lives in 'Layout') to also toggle the state & class (so clicking a link collapses the menu). In jQuery/VanillaJS this was incredibly easy but I can't seem to work out the React/Redux way of doing this.
Layout Component: https://pastebin.com/WzpbeSw7
Header Component: https://pastebin.com/c34NFtUx (probably not relevant but here for reference)
Nav Component: https://pastebin.com/EsJDuLQc
By using redux :
You can have a state like toggleBlaBla : "show" . If you connected your react component to state of redux by using react-redux , whenever you dispatch an action for changing toggleBlaBla to "hide", your connected component will rerender.
By using only react :
If you want two components to change some ui state by some events, it is a good idea to put them in a container component, so that whenever your state changes these two components rerender with your changed state passing to both components.
One way to achieve this is to do the following:
In Layout component:
On line 26 change <Header / > to: <Header handleNavClick={this.toggleNav.bind(this)} / >
In Header component:
On line 10 change <Navigation position="header" /> to: <Navigation closeNav={this.props.handleNavClick.bind(this)} position="header" />
In Navigation component:
On line 16 change return <li key={item._id}><Link to={item.slug}>{item.name}</Link></li> to: return <li key={item._id}><Link to={item.slug} onClick={this.props.closeNav.bind(this)}>{item.name}</Link></li>
Passing the props in this way will allow you to reference reference the toggleNav function inside of Layout and then will update the state accordingly.
*** Note, you may get a binding error such as React component methods may only be bound to the component instance..
If this happens, you will need to define a function on the Navigation component instead of using this.props.closeNav directly. You would need to create a function in Navigation like this: closeNav() { this.props.closeNav.bind(this) }. Don't forget to update the function on the <Link /> component to this.closeNav.bind(this)
Related
Using React & material-ui, I have a pretty big tab container and want to keep data fetches local to each Tab component. I want to be able to essentially greedy load some of the Tab components so as soon as the Tab container is mounted, the Tabs with a greedyLoad prop passed to them are mounted (although not the active tab/visible) and make the fetch for the data they need.
The reason is some of the tabs need a count from the data I fetch in the tab label.
I understand I can fetch the data from the parent component and pass the data as a prop downwards, but I really would like to keep the fetch’s local to each tab component. I’ve seen it done at a previous company I worked at and totally forgot how it worked. Something with CSS I think. Thanks in advance
If you hide the component with CSS, your component will mount on the DOM, but it will be invisible to the user. We just need to add some inline css and make use of the display: none property
function myComponent(show) {
// TODO: fetch the data
return (
<div style={{display: show ? "block" : "none"}}>
<h1 >This component may be invisible!</h1>
<p>{data}</p>
</div>
);
}
I am currently been for 2 days now attempting to get react-reveal to work where it does not require a refresh.
Currently what is happening is when I change page via Link it does not trigger some of the components to animate until I refresh the page.
I have read the documentation and it suggests:
refProp: string If you're using react-reveal component with a custom
React component (like a NavLink from React Router) you must specify
prop name that would be allow access to the DOM. Typically it would be
something like innerRef. By default it is ref. Optional.
So I place in my header.js
let anchorRef = React.createRef();
<Link to="/about" innerRef={anchorRef}>
Then on the about.js page I am getting undefined when I do
constructor(props) {
super(props);
console.log(props.innerRef);
}
This is what I am returning on the page as well as importing the library and etc
<Fade bottom ssrReveal distance="150px">
<p>This is an example</p>
</Fade>
All I am after doing is correctly implementing as suggested in the documents however it would seem I am missing something as I am new to using react.
This is the animation library https://www.react-reveal.com/docs/props/
I am stuck trying pass data from Child A ($emit) component to Parent and from Parent to Child B (props).
Using nuxt.js I have:
layouts/default.vue
This default template will load a lot of components.
Those components will be used or not based on variable from child, the variable will set the v-if directive.
The children are the pages like:
pages/blog/index.vue
pages/about/index.vue
...
The goal is the Child set on Parent what components would be used, the flag can change anytime, the user can choose what will be rendered on admin area.
I have tried use local computed methods on child component, and vuex, no luck with both.
The idea on layouts/default.vue.
<template>
<div>
<TopBar v-if=showTopBar></TopBar>
<Nav v-if=showNav></Nav>
etc...
<nuxt />
</div>
</template>
<script>
import TopBar from "../components/TopBar";
import Nav from "../components/Nav";
etc...
export default {
data() {
return {
showTopBar: false,
showNav: false
etc...
};
},
}
</script>
On child already have use the $emit but no luck.
Child on this situation are pages, and the layout of those pages will be defined by variable from a fetch on the API, user can change the layout anytime.
The goal is have someting like double way between Child Components, example:
Calling route /blog will call pages/blog/index.vue
This would send to layout/default.vue using $emit what components would be rendered (choosed from user in admin area and fetched from API) and the component ID. (example: {topBar: true, topBarID: 2})
On layouts/default.vue after get the $emit from pages/blog/index.vue I would have for example TopBar false, and then not render it, or have received true with an ID, this Id will be send to TopBar as prop for render the customized TopBar made by user on Admin area.
Would be possible someone show an example how to get the pass those data for this specific cenario please?
(Does not matter if using local variables from the Child component or vuex, just looking for an example how to get the contents of variable from Child instead an plain object or undefinied object).
PS.: If there an better approach to deal with dynamic layouts, I am accepting suggestions too.
PS2.: I know I would use specific template per page, like layout/blog and layout/contact, etc... but since the idea is make an CMS, this would not fit on this scenario, I mean, from the admin area user should be able to create pages enabling or disabling components through an page Wizard (the idea is getting something like Wix, every component customization from user will be stored in the database using an Id, and on layouts user choose the previous components mounting the page, in the end all call will be made using the ids of those), and not need to add specific layouts programing, because this the Idea of set all possible components and layouts in layout/default.vue sounds at this moment an better approach, but if is not, I would love see other ways to get same goal.
The correct way to do it would be:
<child-component-1 :showNav.sync="showNav">
And within the child component you would update that by doing:
this.$emit('update:showNav', value)
The parent would define this property:
data() {
return {
showNav: default_value
}
}
You would have to pass that variable to every child component. Every child component would have to define it as a property.
Perhaps a better way to do it would be to instead create a simple store within nuxt and use that to house the settings.
I get the following warning when rendering my component:
Warning: A component is contentEditable and contains children
managed by React. It is now your responsibility to guarantee that none
of those nodes are unexpectedly modified or duplicated. This is
probably not intentional.
This is my component:
import React, { Component } from "react";
export default class Editable extends Component {
render() {
return (
<div contentEditable={true} onBlur={this.props.handleBlur}>
{this.props.children}
</div>
);
}
}
What is the potential problem with my code that React wants to warn me about? I did not quite understand from reading the documentation at https://reactjs.org/docs/dom-elements.html.
I imagine that my component should work exactly like an managed input field, without any problem:
this.props.children is initial value
the onBlur callback updates the props from event.target.innerHTML
the component is rendered with the new props
Setting the contenteditable html attribute allows the contents of that element to be modified in the browser. React is warning you that you have children within that element that are managed by React. React only works from the top down. Meaning it manages a model at the top level and maintains a virtual DOM representing that data, then renders the DOM tree based on that virtual DOM. Any changes you make to the DOM outside of React (such as setting contenteditable and allowing the content to be edited by a user directly in the browser) will be potentially blown away or cause problems for React when it goes to update those managed elements.
In your situation you don't care that the {this.props.children} node gets blown away because you know you're catching the changes and doing what you need to with it. It's just warning you that you better not expect that node to remain intact and accurately updated by React when you're letting the content be edited by the browser directly.
If you know what you're doing (and for now it looks like you do) then you can suppress that warning by adding suppressContentEditableWarning={true}.
Thanks #Chev! It fixed the warnings..
<p
className={editing ? 'editing' : ''}
onClick={editOnClick ? this.toggleEdit : undefined}
contentEditable={editing}
ref={(domNode) => {
this.domElm = domNode;
}}
onBlur={this.save}
onKeyDown={this.handleKeyDown}
{...this.props}
suppressContentEditableWarning={true}
>
{this.props.value}
</p>
I can't find any documentation for how this should be done with the <Navigator/> component... Basically, when one of my scenes loads, I want to be able to, say, pass a route.navBarColor to my navigator that will automatically change the background color of the bar.
I have tried pushing a route with {navBarColor: 'red'}, etc... to renderScene(), but this does not work because renderScene() doesn't seem to have a reference to this, and when I bind(this) it, the entire scene does not render, and throws a Stack Overflow error.
Basically, I want to do something like this:
navigator.push({name: 'TestScene', navBarColor: 'transparent'})
Which then goes to
renderScene(route, navigator) {
if(route.navBarColor) {
this.setState({navBarColor: navBarColor});
} ... etc.
}
Where this.state.navBarColor is used to set the backgroundColor prop of the navigationBar.
Is this possible with the Navigator component? I see that it appears to be with NavigatorIOS, so I don't understand why it wouldn't be here.
Thanks!
The Navigator component has no display of its own, it only manages the scene transitions and routing, so asking how to do this "with Navigator" is not right. This is contrasted with NavigatorIOS which dictates the display as well.
Your question mentions "NavigationBar", is that React Native Navbar?
If yes, somewhere in the renderScene() function there will be a reference to the component, you simply need to pass it the appropriate navBarColor prop.
<NavigationBar statusBar={{ tintColor: route.navBarColor }} />