How to position the react flatpickr inside a container instead of body - reactjs

I am having a use case where i have to position the react flatpickr on the left or right side of the input element instead of above or below.
When using the flatpickr i noticed that the flatpickr gets added to the body of dom. Instead i want to add it to container div. so I am passing the appendTo option with container HTMLElement as value. But its not working as expected and still appending to the body tag.*
here is the code snippet i used.
import React, {useState, useRef} from 'react';
import Flatpickr from 'react-flatpickr';
const DateFilter = props => {
const {setDateTime} = props;
const containerRef = useRef() ;
const container = containerRef.current;
return (
<div ref={containerRef}>
<Flatpickr
appendTo={container}
onChange={date => setDateTime(date)}
enableTime={false}
dateFormat={"Y-m-d"}
/>
</div>
)
}
export default DateFilter;
The calendar still gets added to the body.
Contianer DOM post page load
Clearly i am doing something wrong. Any help is much appreciated. Thanks in Advance.

I found why it was not appending by inspecting the
1. React flatpicker Index.js
2. Core flatpicker.js files
The options (appendTo) wasn't received in react-flatpickr because it should be passed inside an object and not as a direct value.
import React, {useState, useRef} from 'react';
import Flatpickr from 'react-flatpickr';
const DateFilter = props => {
const {setDateTime} = props;
const containerRef = useRef() ;
const container = containerRef.current;
const getOptions = () => {
return {
appendTo : container,
enableTime : false,
dateFormat : "Y-m-d"
}
}
return (
<div ref={containerRef}>
<Flatpickr
onChange={date => setDateTime(date)}
options={getOptions()}
/>
</div>
)
}
export default DateFilter;
And also make sure you pass the correct HTMLElement on the first render. Else if you pass undefined it will still load it in Body.

Related

Cannot read values from array object from the map function in React

I am trying to pass value from an array items object to another component using map(). All values is coming from api call and is showed in console.But when passing the value from here to Titlecard, I am getting error cannot read properties of undefined map()?I have given the code.Also I have shared Titlecard. Always passing only one record into the array Can anyone guide me here? Thanks
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Container } from "react-bootstrap";
import Titlecard from "./Titlecard";
import { HeroesUrl } from "../apiurl/HeroesApi";
const TitleHero = () => {
const [items, setItems] = useState([]);
useEffect(() => {
axios.get(HeroesUrl).then((response) => {
setItems(response.data);
console.log(response.data);
});
}, []);
return (
<>
<Container>
<div>
{items.map((item) => {
return (
<>
<Titlecard key={item.id} item={item} />
</>
);
})}
</div>
</Container>
</>
);
};
export default TitleHero;
import React, { useEffect, useState } from "react";
const Titlecard = (item) => {
return (
<>
<div> item.firstName </div>
</>
);
};
export default Titlecard;
I edit my answer after I saw you shared Titlecard component.
There are 2 problems.
The first is in your return, it should be:
<div>{item.firstName}</div>
Because what you return before is just a string like "item.firstName".
Second, you have to make a destructuring to the props in Titlecard like:
const Titlecard = ({item}) => {...}
or return:
<div>{item.item.firstName}</div>
The first one is your props name, the second is the prop you pass.
So, with using destructuring Titlecard should be like this:
import React from "react";
const Titlecard = ({item}) => {
return (
<>
<div>{item.firstName}</div>
</>
);
};
export default Titlecard;
Please share Titlecard component code.
It's look like that there is a part in the Titlecard component that use the item from the map. In the first time before the axios call finished, the prop item is still empty array, so if you use in the Titlecard component item.something you will get an undefined error.
One solution is to add a loader that initial to true, and after the axios call finished set it to false, so if the loader is true, render a loader, else render your map code.
Another solution is adding ? when you use item in Titlecard component, like: item?.something, what means only if item is not null or undefined.

React using Typewriter effect, re render onInit issue?

So I am working a simple text adventure game using Rails/React.
I am attempting to use the following package: https://www.npmjs.com/package/typewriter-effect
The current functionality has it rendering my dialogue text for the individual storylines.
When I navigate to a new storyline (via a choice) my state updates and re render occurs. But it doesn't re render the new Typewriter effect and associated dialogue.
I have an allTypeWriters variable that creates instance for each storyline. Then I find the relative one based on the newly updated storyLineId.
When I go to the character homepage (navigate away) and then return to the storyline route it will begin the effect with the correctly associated dialogue. If I simply re render via the choice picked, the img tag associated re renders. The choices available re renders. My redux and localStorage all update. Yet the dialogue implemented by the typewriter effect itself stays the same.
I'm assuming it has something to do with the onInit function that belongs to the Typewriter class and I need to recall that? And possibly even remove the previous element after re render.
Any ideas or has anyone worked with this or a similar package in the past, thanks in advance!
import React, { useEffect } from "react";
import "../Dialogue/Dialogue.css";
// import { useEffect, useCallback } from "react";
import Typewriter from "typewriter-effect";
// import { useState } from "react";
// import { useNavigate } from "react-router-dom";
function Dialogue({ storyLine }) {
// const [localWriter, setLocalWriter] = useState({});
const allTypeWriters = JSON.parse(localStorage.getItem("stories")).map(
(story) => {
return (
<Typewriter
options={{
delay: 10,
}}
onInit={(typewriter) => {
typewriter.typeString(story.dialogue).start();
}}
/>
);
}
);
const storyLineId = JSON.parse(
localStorage.getItem("user_data")
).current_storyline;
const returnActive = () => {
const activeType = allTypeWriters.find(() => storyLineId);
return activeType;
};
useEffect(() => {
returnActive();
}, [storyLineId]);
return (
<div className="dialogue-container">
{returnActive()}
<p className="dialogue-img">{storyLine.storyline_img}</p>
</div>
);
}
export default Dialogue;

how to add ref from forwardref component without rendering?

I'm passing a dom node to a mapbox popup.
I've a component P.js which consists of forward ref as
import React from "react";
const P = React.forwardRef((props, ref) => {
return <p {...props} ref={ref}></p>
})
export default P;
I'm importing it in App.js as
import P from './P';
......
const pRef = useRef(null)
console.log(pRef)
const p = <P ref={pRef}/>
console.log(pREf)
const App = () => {
useEffect(() => {
..... //codes
marker.setPopup(new mapboxgl.Popup().setDOMContent(pRef.current))
})
}
How can i pass that ref rendering on another component and running in another?
In my case i tried to make another const to add value
const p = <P ref={pRef}/>
I think, this is not way to passing ref from another component, so it is not rendered.
Is there any methods in Marker component , that i can pass ref if instead to load dom content .
Thank you for helping.
I highly suggest using this react wrapper around the mapbox-gl named react-mapbox-gl
You can do the method mentioned in this tweet and put some style in your P tag to make it invisible by the way
<P class="hide">Hello world</P>
.hide { display: none } /* or any other that fits for you e.g. visibility hidden */
You can also use renderToString to convert your component to HTML string on the fly.
import * as React from 'react';
import { renderToString } from 'react-dom/server';
import mapboxgl from 'mapbox-gl';
const P = React.forwardRef((props, ref) => {
return <p {...props} ref={ref}></p>;
});
export default function App() {
React.useEffect(() => {
marker.setPopup(
new mapboxgl.Popup().setDOMContent(
// render your Paragraph component exactly to html
renderToString(<P>Hello world</P>),
),
);
});
return <div id="map" />;
}
Here is codesandbox for showing it works.
You can also pass the exact same string representation of your paragraph component suggested by a package doc
const popup = new mapboxgl.Popup()
.setHTML('<h1>Hello World!</h1>') // here is the string representation
.addTo(map);
If you want to work with the js package duo to legacy issue, there is also a package that helps you to add a custom tiny react wrapper around the package to work with called react-aptor

Giving child functional component access to Ref defined in parent functional component. useRef()

I need to access "editor" which is a ref defined in my parent component (Editor.js). My child component (Toolbar.js) has function imgChangeHandler which requires editor ref. What is the best way to do this ?
Editor.js (parent):
import React, {useRef, useState} from "react"
const editor = useRef(null);
function Editor() {
...
return (
<>
<div className="center">
<div
className="editor"
style={editorStyle}
ref={editor}
contentEditable={true}
suppressContentEditableWarning={true}
>
<h1>introText</h1>
<p>subText</p>
</div>
</div>
</>
)
}
export default Editor
Toolbar.js (child):
import React, {useState} from "react"
function Toolbar() {
const dispatch = useDispatch();
const inputRef = useRef(null);
const [selectedFile, setSelectedFile] = useState(null);
const imgChangeHandler = e => {
e.preventDefault();
setSelectedFile(e.target.files[0]);
let reader = new FileReader();
let dataURI = reader.result;
const img = React.createElement("img",{src: dataURI});
editor.current.push(img); // need access to editor ref here
if(selectedFile) {
console.log("s");
reader.readAsDataURL(selectedFile)
}
};
...
}
export default Toolbar
In React (almost)everything is done using callbacks. Toolbar should say (in its interface) I need to have a onImgAdded callback so it makes it explicit and it is thought as best practices. (specially if you are using TypeScript to express what the inputs are and if there are any return types expected)
But if you still insist on using ref and passing the ref down for whatever reason it is; in React you can pass props just like you pass arguments to function. So you can do <Toolbar editor={this.editorRef} /> or <Toolbar editor={this.editorRef.current} />

How to use wavesurfer.js in React?

i'm trying to render audio files using wavesurfer.js in my react app. I'm a noob and I'm wondering why I'm getting a "Container element not found" message all the time.
This is what i need to know in a nutshell.
THank you in advance!
import React from "react";
import WaveSurfer from "wavesurfer.js";
export default function Chat(){
const wavesurfer = WaveSurfer.create({
container: "#waveform",
});
render(
<>
<div id="waveform">
</div>
</>
)
}
You are currently calling that in the render function, which would mean it is executed everytime the component refreshes. Instead you can add it in a useEffect hook so that the waveform function is called only once and the element you are binding it to is present.
Also, you can use a ref instead of the ID, which is what React uses to refer to DOM elements.
import React, { useRef, useEffect } from "react";
import WaveSurfer from "wavesurfer.js";
export default function Chat(){
const waveformRef = useRef();
useEffect(() => {
if(waveformRef.current) {
const wavesurfer = WaveSurfer.create({
container: waveformRef.current,
});
}
}, []);
return(
<>
<div ref={waveformRef}>
</div>
</>
)
}
useEffect
Refs

Resources