React onClick event handler not working using Next.js - javascript

I'm making a Reddit clone and I'm using Next.js so its server-side rendered. I started without using Next.js and when I learned about it, I immediately switched to it.
I've created a custom _app.js so the header and sidebar exist on every page, and for it to act as the topmost component to hold application state. The later isn't quite working out.
Here's .project/src/pages/_app.js:
import App, { Container } from 'next/app';
// Components
import Header from '../components/Header/Header';
const MainLayout = props => (
<React.Fragment>
<Header
isSidebarOpen={props.isSidebarOpen}
sidebarToggle={props.sidebarToggle}
/>
{props.children}
</React.Fragment>
);
export default class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
state = {
isSidebarOpen: true
};
sidebarToggle = () => {
this.setState({ isSidebarOpen: !this.state.isSidebarOpen });
};
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<MainLayout
isSidebarOpen={this.state.isSidebarOpen}
sidebarToggle={this.sidebarToggle}
>
<Component {...pageProps} />
</MainLayout>
</Container>
);
}
}
The issue I'm having is, isSidebarOpen and sidebarToggle are being passed to exactly where I need them – they show up in the console – but the onClick handler doesn't activate and if I change isSidebarOpen, it doesn't take effect until I restart the server. I used this approach before using Next.js and it worked as expected.
How can I achieve what I'm trying to do? I've read the docs, searched Google and Stack Overflow. I even checked issues on their repo without luck. I suspect it to be something to do with a custom _app.js, as the props are passed down correctly.

One possibility might be to define your sidebarToggle function within the component you are using.(Maybe because calling it inside Component the code might be running in _app.js instead of your component this is a big maybe! but worth a try)
Here _app.js is a wrapper around your application and I don't think it is suited to be used at the topmost component to hold state. Better to make a simple react root Component do that!

Related

Detect when Screen (Tab) comes to foreground with Class Component and react-navigation: Lifecycle Functions are not working in React-Native

I am using react-navigation 6.x and I am lookin for a way to find out, when a Class Component os focussed. Everything I find online/in the documentation is about functional components, using hooks, because the normal life cycle functions provided by react are not working. So this
componentDidMount () { ..... }
does not work either. However, I need to call a function every time the component is focussed.
How to find out, if a Class Component comes into focus using react-navigation?
There is a way you can actually use the hook in your class component. You will need to wrap your class component with a wrapper that contains the focus hook. Example taken from the documentation.
class Profile extends React.Component {
render() {
// Get it from props
const { isFocused } = this.props;
}
}
// Wrap and export
export default function(props) {
const isFocused = useIsFocused();
return <Profile {...props} isFocused={isFocused} />;
}

Styled Components warning for dynamically imported React components

From a headless CMS I'm fetching the list of components which should be included on certain page. Once fetched, I dynamically import mentioned components like this:
const components = ["Test", "Test2"]; // comes from CMS
const DynamicComponent = ({ name }) => {
let Component;
Component = require(`./components/${name}`).default;
return <Component />;
};
export default function App() {
return (
<Container>
{components.map((comp, i) => (
<DynamicComponent name={comp} key={i} />
))}
</Container>
);
}
And then I just pass these component as children props to some container.
However, although everything works fine, I'm getting some warning for every component I have that says:
The component styled.div with the id of "sc-bdnylx" has been created dynamically.
You may see this warning because you've called styled inside another component.
To resolve this only create new StyledComponents outside of any render method and function component.
I googled the warning but everywhere the solution is to not define styles within the component. I could be wrong, but I don't think that's applicable here.
Here's the full example: https://codesandbox.io/s/style-components-dynamic-5id3y?file=/src/App.js (check the console output)
How can I get rid of this warning?
Thank you
Well, the warning is pretty clear when it says "create new StyledComponents outside of any render method and function component". So what you can do is refactor your functional component DynamicComponent into a class based component
class DynamicComponent extends React.Component {
constructor(props) {
super(props);
this.Component = require(`./components/${this.props.name}`).default;
}
render() {
return <this.Component />;
}
};
EDIT: tested on your sandbox, made the fixes to my previous code, and your warnings are gone

Why aren't my props available to use in my component when I need them?

I keep running into similar issues like this, so I must not fully understand the lifecycle of React. I've read a lot about it, but still, can't quite figure out the workflow in my own examples.
I am trying to use props in a child component, but when I reference them using this.props.item, I get an issue that the props are undefined. However, if the app loads and then I use the React Browser tools, I can see that my component did in fact get the props.
I've tried using componentDidMount and shouldComponentUpdate in order to receive the props, but I still can't seem to use props. It always just says undefined.
Is there something I'm missing in React that will allow me to better use props/state in child components? Here's my code to better illustrate the issue:
class Dashboard extends Component {
state = { reviews: [] }
componentDidMount () {
let url = 'example.com'
axios.get(url)
.then(res => {
this.setState({reviews: res.data })
})
}
render() {
return(
<div>
<TopReviews reviews={this.state.reviews} />
</div>
);
}
}
export default Dashboard;
And then my TopReviews component:
class TopReviews extends Component {
state = { sortedReviews: []}
componentDidMount = () => {
if (this.props.reviews.length > 0) {
this.sortArr(this.props.reviews)
} else {
return <Loader />
}
}
sortArr = (reviews) => {
let sortedReviews = reviews.sort(function(a,b){return b-a});
this.setState({sortedReviews})
}
render() {
return (
<div>
{console.log(this.state.sortedReviews)}
</div>
);
}
}
export default TopReviews;
I'm wanting my console.log to output the sortedReviews state, but it can never actually setState because props are undefined at that point in my code. However, props are there after everything loads.
Obviously I'm new to React, so any guidance is appreciated. Thanks!
React renders your component multiple times. So you probably see an error when it is rendered first and the props aren't filled yet. Then it re-renders once they are there.
The easy fix for this would be to conditionally render the content, like
<div>
{ this.props.something ? { this.props.something} : null }
</div>
I would also try and avoid tapping into the react lifecycle callbacks. You can always sort before render, like <div>{this.props.something ? sort(this.props.something) : null}</div>
componentDidMount is also very early, try componentDidUpdate. But even there, make your that your props are present.
For reference: see react's component documentation

function inside stateless component

before someone as this duplicate to this question
Can you write nested functions in JavaScript?
I am wondering if we can do something like this?
const toolbar = (props) => {
let sidedrawer = false;
showSideDrawer = () => {
sidedrawer = !sidedrawer
}
return (
<header className={Classes.Toolbar} purchasingHandlerClose={this.showSideDrawer}>
//Something here
</header>
)
}
export default toolbar;
More precisely, something like this in functional component
showSideDrawer = () => {
sidedrawer = !sidedrawer
}
and then calling it like this
<header className={Classes.Toolbar} purchasingHandlerClose={this.showSideDrawer}>
Now, I know we can do this stateful component or class but then again in JS, Class is just syntactical sugar (still trying to figure out the meaning of the phrase), so how can we implement something like this in stateless or functional component?
You can write a function within a stateless functional component, however function component don't have a this variable and in order to call the function you would simply write
const toolbar = (props) => {
let sidedrawer = false;
const showSideDrawer = () => {
sidedrawer = !sidedrawer
}
return (
<header className={Classes.Toolbar} purchasingHandlerClose={showSideDrawer}>
//Something here
</header>
)
}
export default toolbar;
However one pitfall of the above is that everytime the toolbar component is rendered sidedrawer is initiased to false and hence the showSideDrawer doesn't work as expected. You can however move the sidedrawer variable outside of functional scope and it will work
let sidedrawer = false;
const toolbar = (props) => {
const showSideDrawer = () => {
sidedrawer = !sidedrawer
}
return (
<header className={Classes.Toolbar} purchasingHandlerClose={showSideDrawer}>
//Something here
</header>
)
}
export default toolbar;
However in this case too, the showSideDrawer function is also created everytime toolbar is render which isn't the right way to do and hence if you want to have such a functionality its always advisable to write a class component instead of a functional component because functional components are supposed to be pure..
You can write nested function as this is concept of JavaScript. But as Reactjs, it re-render only if props or state change. So if you update any local variable or this.something, It will not reflect on UI. It can show on UI only if parent state or props changes and React thing about this compenent should update.
If you want to update UI based on variable, state or props should update. So either you have to pass to props and handle state in parent or you have to create stateful component.
You might be trying to get something different, please share you scenario. Might be we can find a proper way based on situation.

Integrating and rendering react-swipe-cards

I am very noob with reactJs, in fact I just finished this course and am struggling with some concepts here.
I am willing to create an app for people to express their preferences with regards of subjects for a newsletter, and have grabbed a very comprehensive list of topics (2k+) and wanna make some fun way to select them, so I think that something along the lines of Tinder swipeable cards would be a perfect fit, so I am trying to implement this react module functionality into my App.
But it is not showing up anything.
I just created a Repo, in which I had a few tries with no luck.
Basically, the example provided in the module documentation says that it should start by
const data = ['Alexandre', 'Thomas', 'Lucien', 'Raphael', 'Donatello', 'Michelangelo', 'Leonardo']
const Wrapper = () => {
return (
<Cards onEnd={console.log("action('end')")} className='master-root'>
{data.map(item =>
<Card
onSwipeLeft={console.log("action('swipe left')")}
onSwipeRight={console.log("action('swipe right')")}>
<h2>{item}</h2>
</Card>
)}
</Cards>
)
}
But I am completely lost with it, I supposed that it should provide me with a React Component <Something />, but instead it generate something in the lines of a function, that returns a div, which looks a lot with a component, but I have no idea about how integrate into this example.
Note: In the repo graph, I noticed that there is another developer that made some adjustments to make it compatible with react 16.xx.beta, I'v tried it also, no lucky also.
I am almost sure, that there are some concepts I am missing here, so, any reference is more than welcome, also.
What you are looking for is a functional stateless component, the below code
const Wrapper = () => {
return (
<Cards onEnd={console.log("action('end')")} className='master-root'>
{data.map(item =>
<Card
key={item}
onSwipeLeft={() => {console.log("action('swipe left')")}}
onSwipeRight={() => {console.log("action('swipe right')")}}>
<h2>{item}</h2>
</Card>
)}
</Cards>
)
}
is a functional component.
According to documentation
Functional and Class Components
The simplest way to define a component is to write a JavaScript
function:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
This function is a valid React component because it accepts a single
“props” (which stands for properties) object argument with data and
returns a React element. We call such components “functional” because
they are literally JavaScript functions.
The way to render a function component is just like you would render a normal React component
<Wrapper {...props} /> // {...props} is a spread operator syntax to just pass all the props down to wrapper you can pass selected props too
Also react-swipe-card doesn't provide you Wrapper functional component, it provides you components like Cards and Card which you used to render the card view in the Wrapper Component
import Cards, { Card } from 'react-swipe-card'
Now in your case it would look like
export default class MyCards extends Component {
render() {
return <Wrapper />;
}
}
However since you don't have a state and also you are not using lifecycle functions you could simple write the above MyCards Component as
export const MyCards= () => {
return <Wrapper />;
}
I however assume that you would eventually be writing some of the logic there and hence keep it a stateful React component. I have also include the logic whereby you would handle the state change on left or write swipe.
Check a working DEMO
P.S. I a recommendation to go through the React docs thoroughly as they have explained the concepts really well
If I understand you question as suppose. It look you have some small mistake. I download the repo and run you test on React 15.4.2
Your Card component call:
<Card
onSwipeLeft={console.log("action('swipe left')")}
onSwipeRight={console.log("action('swipe right')")}>
<h2>{item}</h2>
</Card>
My Card component call:
<Card
key={item}
onSwipeLeft={()=>{console.log("action('swipe left')")}}
onSwipeRight={() => {console.log("action('swipe right')")}}>
<h2>{item}</h2>
</Card>
We need to create scope for events handler that is why one of the solution is a arrow function. They aren’t just syntactic sugar around anonymous functions though. An arrow function does not have its own context and will instead use the same this as the context in which it was defined. Here is more detail handle-events-in-react-with-arrow-functions
Also on the MyCards you are returning something like (your code)
export default class MyCards extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return Wrapper;
// return (
// <div>
// <p>Something</p>
// {Wrapper();}
// </div>
// );
}
}
But you should return a component and the way is return it have to be
export default class MyCards extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return <Wrapper/>
}
}
Suggestion: If you are not going to have any state in the MyCards component you can make it a functional Component
The current top answer is correct and great about the concept of the functional component. You are actually creating a High Order Component.
However I feel your repo can actually be fixed by just making this change:
render() {
return Wrapper();
}
See that I actually executed the Wrapper function in order to get the Component as a result, otherwise you are rendering a function and not a Component.
You can refactor your code to actually extend a React.Component, and I actually recommend this as HOC are better used for another type of objective, like decorators.
See here, the only thing I changed is that: https://codesandbox.io/s/xp6pzpyoq

Categories

Resources