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/
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'm using Gatbsy and I'm trying to create an accessibility link for the users (using screen readers) to be able to navigate to content (skipping the navigation).
My layout component (which is used in every page of the website) looks something like this:
const Layout = ({ children }) => {
{/* hidden for brevity */}
return (
<>
Skip to content {/* <-reference line */}
{/* hidden for brevity */}
<main id="main-content">
{children}
</main>
{/* hidden for brevity */}
</>
);
}
Current behaviour:
As it's shown in the code example above the link will be generated once for the page I'm "landing on", and it will not update for subsequent pages I navigate to:
ex. landing on the 'blog' page my link will point to localhost:9000/blog#main-content and navigating to 'about' page will not make that section of the layout re-render (this is most likely normal behaviour).
I also tried using useRef, but got the referenced item being undefined during rendering.
What would be the way to complete this task (considering that the pages are server-side-rendered)? Is there a way I could do it without passing the full route path to use it inside the tag?
As I commented above, Gatsby's <Link> component extends from #reach/router (from React) doesn't allow navigating to any parameter. From the docs:
Neither <Link> nor navigate can be used for in-route navigation with a
hash or query parameter. If you need this behavior, you should either
use an anchor tag or import the #reach/router package—which Gatsby
already depends upon—to make use of its navigate function.
If you use navigate, for example, navigate("/blog#main-content") it will redirect to /blog, omitting the parameter since it's not allowed.
In your case, the useRef approach won't directly since at the moment you are creating it, it's not still rendered so, you can use the useRef hook approach alongside with useEffect hook, to ensure that the DOM tree is loaded or using some manual trigger:
const Layout = ({ children }) => {
const mainRef= useRef(null);
const navigateToContent= () => {
mainRef.current.scrollIntoView(); //manual trigger
}
useEffect(()=>{
mainRef.current.scrollIntoView(); //automatic trigger
}, [])
{/* hidden for brevity */}
return (
<>
<div onClick={navigateToContent}>Skip to content</div>
{/* hidden for brevity */}
<main id="main-content" ref={mainRef}>
{children}
</main>
{/* hidden for brevity */}
</>
);
}
In the snippet above I've added two different approaches, choose the one that fits your requeriements. The key part is to set correctly the reference of the main tag, initially set as null to avoid rehydration issues when the routing changes.
The manual trigger, just call a function (navigateToContent) in your Skip to content
element that uses the scrollIntoView() built-in function to scroll to the reference.
The automatic trigger, just uses the same idea but the function is triggered once the DOM tree is loaded (useEffect with empty deps, []).
The issue has been solved as following:
Actually changing this <Link to="/#main-content">Skip to content</Link> to this <Link to="#main-content">Skip to content</Link>
(removing the /) works perfectly fine
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'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)
I have a component which, in componentDidMount, gives a jQuery plugin some control over the DOM rendered by React. I know everyone says "never let anything but React touch the DOM", but hear me out, as reinventing this plugin is not feasible right now, and I think there should be an "overwrite whatever you find in the DOM" switch for React that I hope someone can point me to.
More info: I've designed it so the state of the React's DOM is entirely determined from the props given to React except while the user is dragging things around. Once dropped, I don't care how the DOM changed since the last React update, I just want to render everything from the current props of React, which I am passing in on the plugin's change handler via ReactDOM.render
The symptoms are that the nodes created by the plugin during and after dragging don't go away after React is told to update!
Yes, the nodes are key-ed initially.
The plugin is Nestable, and it adds interactivity (drag-drop reordering of the tree), and a JSBin is here: http://jsbin.com/qareki/edit?js,console,output
I'm really looking for the "Kill whatever you find" setting. I thought calling ReactDOM.render would do it, but it's clearly not doing it. Neither of course, was the more surgical setState, but I didn't expect it to. Thanks in advance for all 'you're doing-it-wrong' advice and other fixe
Manually add a div element in componentDidMount and replace it with a new one in componentDidUpdate:
class Foo extends React.Component {
render() {
// whatever HTML you want...
return (
<div>
<div>
{/* this div will contain our non-React stuff that we need to reset */}
<div ref="container"></div>
</div>
</div>);
}
blastAndRecreate() {
// throw away any content within the container and replace it with brand new content
const container = $(this.refs.container).empty();
const newDIV = $("<div>").appendTo(container);
// give this new DIV to nestable plugin
newDIV.nestable(...);
}
componentDidMount() {
this.blastAndRecreate();
}
componentDidUpdate() {
this.blastAndRecreate();
}
}