Integrating and rendering react-swipe-cards - javascript

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

Related

React changing text of child on button hover

I want to change the text of a child function component when I hover over a button of my parent class component. I'm having trouble accessing the prop though in the child component and getting null. Any help is appreciated
parent component:
export default class PathfindingVisualizer extends React.Component {
constructor(props) {
super(props)
this.state = {
AlgoDef: null,
};
}
render() {
return (
<React.Fragment>
<div className="button-bar"> //buttons that change state
<button
onClick={() => this.helperDikjstras()}
onMouseOver={() => this.setState({ AlgoDef: "Dikj"})}
>Dikjstras</button>
<button
onClick={() => this.helperAstar()}
onMouseOver={() => this.setState({ AlgoDef: "Astar"})}
>A*</button>
</div>
<div>
<AlgoExplaination algoName={this.AlgoDef} /> //changes its text based on state of parent
</div>
</React.Fragment>
);
}
}
my child component:
export default function AlgoExplaination(props) {
const [text, setText] = useState("default");
useEffect(() => {
switch (props) {
case "Dikj":
setText("Dikjstra");
break;
case "Astar":
setText("Astar");
break;
default:
setText("useEff");
}
//console.log(`text: ${text}`);
//console.log(props);
// console.log(props.algoName);
});
return (
<div>
<p>{text}</p>
</div>
)
}
both console logging props gives me: {algoName: null}. and props.algoName gives me null
As #Rajesh has mentioned in a comment, you are passing props to your AlgoExplaination (sic) component incorrectly like this:
<AlgoExplaination algoName={this.AlgoDef} />
You intended to pass the AlgoDef property of your state, which is this.state.AlgoDef, so change accordingly to this:
<AlgoExplaination algoName={this.state.AlgoDef} />
Furthermore, when you access the algoName property of your props, you currently attempt to access it as if it were the props object itself incorrectly like this:
switch (props) {
The props object for AlgoExplaination will be an object with an algoName property that looks (partially) like this:
{ algoName: "Dikj" }
So, the value you need is actually stored in props.algoName. Therefore, please change accordingly to this:
switch (props.algoName) {
As #Wyck has addressed most of the points, I'll focus this answer on the last point:
Third, why do you have both class component and functional component with hooks? Please use 1 way
Class vs Functional component
In theory, a class component has lifecycle events and state, where as a functional component is just a function that returns JSX.Element. Such components were called stateless.
Because of this, class component had a bit of overhead over functional component, and as a performant option functional component were preferred.
Hooks
Hooks are a way in react to give functional components access to have its own state and few major lifecycle events. This is achieved using closure (not going in full depth) and craftsmanship. This also makes class components obsolete as everything can be achieved in functional component.
Which one to use?
As a preference, its suggested to use functional component with hooks as they are easy to use and are performant as well, in comparison.
Why to use one?
In general programming practice, as a developer, you should use a single way to do things. Benefit of this is, it helps in fast reading.
If I use a for loop in one section and a Array.forEach in next, as a developer, I will be asked to read and understand the purpose. This adds overhead and reduces readability. Having same approach moves the focus of reader to just the logic.
I recomend you to destructuring the props, to be more clear.
In
export default function AlgoExplaination(props)
Can be something like:
export default function AlgoExplaination({algoName})
So you can use it in your switch statment.
switch (algoName) {
case "Dikj":
setText("Dikjstra");
Right now, you are passing all props but you will have to access as props.algoName in the switch statment.

Render Props vs HOC?

I'm trying to learn React from scratch and having a deep knowledge of concepts !
Today I was searching about HOC, Render Props and the differences between the two. I've checked render times for both. I wrote a console.log('rendered') into render to check render times in browser console.
HOC: When I used HOC to write an usable component, I saw after each changes on props I've render for HOC and component that used HOC.
Render Prop: In this case I've changed the props, but only wrapper component has rendered. because with render props we load only one component and inject codes to use that component feature !
So, Is it a benefit to use Render Props instead HOC components? Or HOC components are usable and powerful yet?
Thanks
HOC, Render Props and now hooks all serve to the same purpose: Share stateful logic between components. There is actually no way to tell which one is better or worst. All depends on your use case.
High Order Components are composable. It's easy to nest them
const withProps = (Component) => connect(mapState, mapDispatch)(<Component foo='bar' />)
Children as a function is a bad pattern for composability, nesting looks a lot like a callback hell cause they need to be executed inside an jsx block
const Component = () =>{
return(
<Consumer>
{
props =>(
<ThemeConsumer>
{
theme => <Child {...props} {...theme} />
}
</ThemeConsumer>
)
}
</Consumer>
)
}
On the other hand, render props it's easy to set up, have less boilerplate and in most cases are easier to reason about.
Hooks bring the best of both worlds
hooks are composable, can be easily nested, and are simple to reason about cause after all they're just plain old functions
const useConfig = () =>{
const customProps = useCustomProps()
const theme = useContext(ThemeContext)
return [customProps, theme]
}
const Component = () =>{
const [props, theme] = useConfig()
}
But again: There is no such thing as the best pattern. It's just a matter of where are you going to use it.

useContext only works in stateless functional component

I'm trying to get to grips with the new useContext function in React. Works great in stateless functionality components. For example:
import React from 'react';
import LocaleContext from '../LocaleContext';
const Link = ({ text, url }) => {
const locale = useContext(LocaleContext);
return (
<a href={`/${locale}/${url}`}>
{text}
</a>
);
};
export default Link;
I also want to use useContext in stateful components, and even non React functions, but when I do so, I get the following error:
Hooks can only be called inside the body of a function component.
The message seems simple enough to understand, but is this really true? I can only use it in a stateless functional component? If so, it seems kind of pointless to me, because it's super easy to use a simple HOC or the traditional method of:
<Locale Consumer>
{locale => (
...
)}
</LocaleConsumer>
So what gives here? I have the latest version of every package in my project. Not sure if it matters but I'm developing a NextJS site here.
If you really want to use classes (i actually came from Angular and i still prefer use classes) you can workaround easily like that:
class ComponentImpl extends React.Component<any> {
constructor(props?) {
super(props);
}
render() {
return (
<div>
CounterButton: <button onClick={() => {this.props.appContext.setCount(this.props.appContext.count + 5)}}>App Counter + 5</button>
</div>
)
}
}
export function Component() {
let appContext = useContext(AppContext);
return <ComponentImpl appContext={appContext}></ComponentImpl>
};
And you just use it: <Component></Component>
The problem is what the error says. React hooks aren't available in class components. Due to differences between class components and function components, hooks cannot be used with the former.
As the documentation says,
Hooks let you use more of React’s features without classes. Conceptually, React components have always been closer to functions. Hooks embrace functions, but without sacrificing the practical spirit of React. Hooks provide access to imperative escape hatches and don’t require you to learn complex functional or reactive programming techniques.
Hooks are supposed to address common use cases that are specific to class components which couldn't be previously implemented with stateless functional components alone. Functional components aren't stateless since React 16.8 and are allowed to have a state and trigger own updates.
As for useContext hook,
When the provider updates, this Hook will trigger a rerender with the latest context value.
It would be messed up in class component due to difference between functional and class components. Component function is called each time the component is rendered:
const Foo = props => {
const context = useContext(Context);
// use context
}
There's no place in class component that would behave the same way except render function. And if lifecycle-specific tasks go to render function, this means that a class was a wrong choice, and class component needs to be refactored to a function. A counterpart to useContext in class components is contextType, which is currently restricted to single context.
For multiple contexts it's still required to receive them through context Consumer inside render, or as props from higher-order component wrapper:
const contextsHOC = (contexts = {}) => Comp => (
props => {
const contextProps = {};
for (const prop in contexts) {
// eslint-disable-next-line react-hooks/exhaustive-deps
contextProps[prop] = React.useContext(contexts[prop]);
}
return <Comp {...props} {...contextProps}/>;
}
);
#contextsHOC({ bar: BarContext, baz: BazContext });
export default class FooComponent extends Component {
// contexts are mapped to this.props.bar and this.props.baz
...
}
// or
class FooComponent extends Component { ... }
export default contextsHOC({ ... })(FooComponent);
Passing contexts as props allows for additional optimization with PureComponent or shouldComponentUpdate.
useContext is a hook that consumes a context and can only be used in functional components.
If you want to consume context in class components, you will need to look at alternative methods such as Consumer Component, official docs for this here

React context props drilling, what is it that I don't get?

There is a TL;DR at the bottom.
I am probably doing this wrong or using the context in an bad way. I am new to react so I have no clue if this is how we are meant to do things.
My understanding:
Context can be used to pass down props to deeper nested child components without having to pass them through all levels of nesting. A provider is filled with props, and a consumer will look "up the tree" to find the nearest provider and get it's data.
If this is the case, then I can load a provider with a function, such as an onChange handler in order to avoid having to write the handler on every child component when they all do the same thing. This would allow for a "smart form" which govern's its input's handlers by "passing" handlers given to it. Obviously just writing one handler on multiple components is not an issue, but having like 20-30 form fields and writing 4+ handlers on each of them just creates code clutter. So I tried the following:
HTML structure is like this, for example:
<ControlledForm data={some_data} handlers={some_handlers}>
<LabeledControl name="Type your name" rel="Name" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Pet name" rel="PetName" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Type of pet" rel="PetType" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Family" rel="Family" meta={{some_meta_object}}></LabeledControl>
</ControlledForm>
And this is the ControlledForm class code:
const { Provider } = React.createContext(); //Note this
class ControlledForm extends Component {
state = {};
render() {
return (
<Provider value={{ onChange: this.props.onChange }}>
<form>{this.props.children}</form>
</Provider>
);
}
}
Now whatever child I place within this form would want to have a <Consumer> wrapper around it to consume the changeHandler, or at least this is the plan. However when I wrap my LabeledControl in a consumer, it acts as if it has no data.
<LabeledControl> (reduced code):
const { Consumer } = React.createContext();
class LabeledControl extends Component {
state = {};
render() {
return (
<Consumer>
{r => {
console.log("consumer:", r); //Logs undefined
return (
<div className="labeled-control">
{/*Code here*/}
</div>
);
}}
</Consumer>
);
}
}
If I was to guess at what the issue is, I'd say it is because both the ControlledForm and the LabeledControl create it's own context, which is not shared, look at the code above. But I do not understand how would I share this context and still keep the two classes in separate .js files. I cannot pass a reference down to the children, all I get is the {this.props.children} and no way to tell it "Hey use this provider here". All the examples I find online have the two classes that are a provider and a consumer in a same file, being able to reference the same "context" but this seriously impacts the freedom of what I can put inside a form, or rather doesn't let me have customization in terms of "children".
TLDR
How do I pass down a "Context" from a Provider to a Consumer when they are in two different javascript files? Code is above. I essentially need to pass down a handler to every child and have it (maybe, maybe not, depending on a child) use the handler to tell the parent to update it's data. All of this whilst using {this.props.children} in a parent in order to allow "outter code" to "inject" the parent component with any children desired and have them either use or not use the parent's handler.
Edit:
I searched about a bit and found two possible solutions, which I both tested and both seem to be working (with a limited use case). Both render props and React.CloneElement seem to do the trick when there is one level of nesting as we can directly render and add props to children with them, but when we need to prop drill several levels, all the components in between would have to implement the same passing of props which then turns to spaghetti code. Still searching to try and find the way to pass the context down to the children for consumption in different files.
Please view the code below.
Also: here is a sample project I have built:https://codesandbox.io/s/5z62q8qnox
import React from 'react'
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
export default class ControllerForm extends React.Component {
static childContextTypes = {
onChange: PropTypes.func.isRequired
}
getChildContext() {
return {
onChange: this.handleOnChange
}
}
handleOnChange = (e) => {
console.log(e.target.value) //here is the place you have to implement
}
render() {
return (
<div class="container">
{this.props.children}
</div>
)
}
}
import React from 'react'
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
export default class LabeledControl extends React.Component {
static contextTypes ={
onChange : PropTypes.func.isRequired
}
render() {
return (
<div>
<div className="form-group">
<input className="form-control" type="text" onChange={this.context.onChange} />
</div>
</div>
)
}
}
function App() {
return (
<div className="App">
<ControllerForm>
<LabeledControl />
<LabeledControl />
</ControllerForm>
</div>
);
}
It appears that Context is not what I should be using for this, instead either render props or React.cloneElement() is the proper solution, despite my best efforts to enforce a context.
Parent's render:
{this.props.children.map((child, index) =>
React.cloneElement(child, { key: index, handler: handler })
)}
Child's render:
return (
<div>
<span onClick={this.props.handler}>{passed.foo}</span>
</div>
);
This way the structure remains clean and handlers get passed down. Only issue is every component that needs to pass them down has to implement this, but it would have been the same with context, since it is not exported to a separate file.

Storing methods needed in all components

I have a universal app I'm developing for learning purposes. I'm managing the state of my app with Redux, so all my data will be available there. But I want to create some methods that I'm going to use in all my components. The problem is: where should I store this methods?
Adding them to a parent component and passing the methods as props doesn't seem very useful, because this is one of the things that Redux tries to solve. And I'm pretty sure that Redux is not a place for storing methods.
I know I can create a class in a file somewhere, export it, add some methods to it, and when I want to use one method in a component I can call this file, create an instance of the class and call the needed method; but this doesn't look very react to me…
Is there a right way to create methods available for all components?
I've had some success sharing functions between components using an approach similar to the following. I'm not sure this approach will solve your specific use case with regards to cookies, however.
These functions can be stored anywhere and imported wherever required. They accept a component as their first argument, then return a function that operates on the component passed in.
Indicative, untested code follows.
// An event handler than can be shared between multiple components
const handleChange = component => event => component.setState({ value: event.target.value });
class ComponentOne extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
class ComponentTwo extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}

Categories

Resources