import React, { Component } from 'react';
import ChatBot from 'react-simple-chatbot';
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import Dropzone from 'react-dropzone';
class Form extends Component {
constructor(props){
super(props);
this.state = {
// some other states
file: ''
};
}
onDrop(acceptedFiles){
var file = acceptedFiles[0];
const reader = new FileReader();
reader.onload = () => {
const fileAsBinaryString = reader.result;
this.setState({
file: fileAsBinaryString
});
//console.log(fileAsBinaryString);
}
reader.readAsBinaryString(file);
//console.log(file);
}
render() {
return(
<ChatBot
steps={[
{
id: '1',
message: 'You can add custom components',
trigger: '2',
},
{
id: '2',
component: (
<div>
<Dropzone onDrop={this.onDrop.bind(this)} />
</div>
),
end: true,
},
]}
/>
)
}
}
I am trying to use react-dropzone within react-simple-chatbot, but when I upload a file it shows 2 warnings:
React does not recognize the previousStep prop on a DOM element.
React does not recognize the triggerNextStepenter image description here prop on a DOM element.
I am able to find similar problems but their solutions are not working out for me. How should I make it work?
Edit: I have added an example similar to my approach.
Hello Dear your question is not not clear to me as it lacks lots of information,It would have better if you put your code here. I don't know did you follow react-dropzone documentation. In their documentation they cleared how to use it in your application. Try to do below procedure. In my case it is working without showing any warning.
import Dropzone from 'react-dropzone'
//OTHERS IMPORT FILE
// ... ... ...
class AddEmployee extends Component {
constructor(props) {
super(props);
this.state = {
photo: ""
}
}
// OTHERS FUNCTIONS
// ... ... ....
onDrop(files) {
const file = files.find(f => f)
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
this.setState({
photo: reader.result,
})
}
}
render() {
return (
// OTHERS DIV
// ... ... ... ...
<div className="dropzone">
<Dropzone onDrop={(e) => this.onDrop(e)}>
{this.state.photo != "" ? <img width={195} height={195} src={this.state.photo} /> : <p>Try dropping some photo here or click to select files to upload</p>
}
</Dropzone>
</div>
// OTHERS DIV
// ... ... ... ...
)
}
}
Related
Wassup Guys,
I have a reusable component, that translates keys into a choosen language through keynames as string or a binded var.
Usually I use a tag for this, but because of different reasons I am switching/replacing current translations with {t('...')}.
Here is the code of the component:
import React from 'react';
import { useTranslation as defaultTranslation } from 'react-i18next';
import i18next from 'i18next';
export const useTranslation = (ns = 'common', options) => {
return defaultTranslation(ns, {
useSuspense: false,
...options,
});
};
export const withTranslation = (Component, ns, options) => {
const TranslatedHOC = (props) => {
const translationProps = useTranslation(ns, options);
return <Component {...translationProps} {...props} />;
};
return TranslatedHOC;
};
export const getCurrentLanguage = () =>
i18next.language || localStorage.getItem('language') || 'de-DE';
First of all I define the const for the used imported function:
const {t} = useTranslation();
normal case: importing my component in the file, where I want to use it and add code above.
Code of my component, where I want to replace the Tags.
// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';
import LocalizedText from '#components/i18n/LocalizedText';
class T extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
pages: null,
loading: true,
};
this.fetchData = this.fetchData.bind(this);
}
fetchData(state, instance) {
this.props.onFetchData(state, instance).then(() => {
this.setState({
loading: false,
});
});
}
render() {
return (
<ReactTable
{...this.props}
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
nextText={
<LocalizedText textKey="caseoverview.orderproduct.continue" />
}
loadingText={<LocalizedText textKey="loading" />}
noDataText={<LocalizedText textKey="placeholders.nodata" />}
pageText={
<LocalizedText textKey="reservationcalculator.search.result.page" />
}
ofText={<LocalizedText textKey="from" />}
rowsText={<LocalizedText textKey="rows" />}
className="case-search-table"
/>
);
}
}
export default T;
...
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
...
should change to:
...
previousText={
t('caseoverview.orderproduct.back')
}
...
The problem is, that I can't use the code quoted above without getting any issues regarding invalid hook calls. If I move it out somehow, I get errors telling me that my 't' is either not defined or an unexpected token. Could someone help me out? Searched online for solutios without any result.
A hook can only be used in a functional component. You can change this class component to a functional component, or you can use react-i18next's withTranslation HOC to wrap your class component. See https://react.i18next.com/latest/withtranslation-hoc#when-to-use
#kevin asworth answer helped me out.
Using withTranslation with passing t as prop
const {t} = this.props;
inside the render method worked for me.
I am trying to get EditorJS working in NextJS. The editor loads fine without plugins, having the only paragraph as a block option. However, when I attempt to add plugins via tools prop console throws the following warning:
editor.js?9336:2 Module Tools was skipped because of TypeError: Cannot read property 'prepare' of undefined
When I click on the editor in the browser, it is throwing:
Uncaught TypeError: Cannot read property 'holder' of undefined
I have tested editor plugins in the normal React app, and they load fine. Meaning that the problem is in EditorJS and NextJS import and handling of plugins. I have tried to import editor and plugins in componentDidMount hook using require but had the same problem as with NextJS dynamic imports. Attempted to get component using React ref but found that currently NextJS has problems with getting components' refs, Tried suggested workaround but still had no result. The instance of the editor is not available until onChange is triggered, so plugins just cannot hook into the editor due to that 'prepare' property or the whole editor are being undefined until an event on editor has happened, but the editor outputs into the console that it is ready.
My component's code:
import React from "react";
import dynamic from "next/dynamic";
const EditorNoSSR = dynamic(() => import("react-editor-js"), { ssr: false });
const Embed = dynamic(() => import("#editorjs/embed"), { ssr: false });
class Editor extends React.Component {
state = {
editorContent: {
blocks: [
{
data: {
text: "Test text",
},
type: "paragraph",
},
],
},
};
constructor(props) {
super(props);
this.editorRef = React.createRef();
}
componentDidMount() {
console.log(this.editorRef.current);
console.log(this.editorInstance);
}
onEdit(api, newData) {
console.log(this.editorRef.current);
console.log(this.editorInstance);
this.setState({ editorContent: newData });
}
render() {
return (
<EditorNoSSR
data={this.state.editorContent}
onChange={(api, newData) => this.onEdit(api, newData)}
tools={{ embed: Embed }}
ref={(el) => {
this.editorRef = el;
}}
instanceRef={(instance) => (this.editorInstance = instance)}
/>
);
}
}
export default Editor;
Is there any solution to this problem? I know SSR is challenging with client side rendering of components that access DOM, but there was condition used that checked whether window object is undefined, however, it does not look like an issue in my situation.
UPDATE:
I have found a solution but it is rather not a NextJS way of solving the problem, however, it works. It does not require a react-editorjs and implemented as creation of EditorJS instance as with normal EditorJS.
class Editor extends React.Component {
constructor(props) {
super(props);
this.editor = null;
}
async componentDidMount() {
this.initEditor();
}
initEditor = () => {
const EditorJS = require("#editorjs/editorjs");
const Header = require("#editorjs/header");
const Embed = require("#editorjs/embed");
const Delimiter = require("#editorjs/delimiter");
const List = require("#editorjs/list");
const InlineCode = require("#editorjs/inline-code");
const Table = require("#editorjs/table");
const Quote = require("#editorjs/quote");
const Code = require("#editorjs/code");
const Marker = require("#editorjs/marker");
const Checklist = require("#editorjs/checklist");
let content = null;
if (this.props.data !== undefined) {
content = this.props.data;
}
this.editor = new EditorJS({
holder: "editorjs",
logLevel: "ERROR",
tools: {
header: Header,
embed: {
class: Embed,
config: {
services: {
youtube: true,
coub: true,
},
},
},
list: List,
inlineCode: InlineCode,
code: Code,
table: Table,
quote: Quote,
marker: Marker,
checkList: Checklist,
delimiter: Delimiter,
},
data: content,
});
};
async onSave(e) {
let data = await this.editor.saver.save();
this.props.save(data);
}
render() {
return (
<>
<button onClick={(e) => this.onSave(e)}>Save</button>
<div id={"editorjs"} onChange={(e) => this.onChange(e)}></div>
</>
);
}
}
This implementation works in NextJS
I will update code if I find a better solution.
UPDATE 2:
The answer suggested by Rising Odegua is working.
You have to create a seperate component and then import all your tools there:
import EditorJs from "react-editor-js";
import Embed from "#editorjs/embed";
import Table from "#editorjs/table";
import List from "#editorjs/list";
import Warning from "#editorjs/warning";
import Code from "#editorjs/code";
import LinkTool from "#editorjs/link";
import Image from "#editorjs/image";
import Raw from "#editorjs/raw";
import Header from "#editorjs/header";
import Quote from "#editorjs/quote";
import Marker from "#editorjs/marker";
import CheckList from "#editorjs/checklist";
import Delimiter from "#editorjs/delimiter";
import InlineCode from "#editorjs/inline-code";
import SimpleImage from "#editorjs/simple-image";
const CustomEditor = () => {
const EDITOR_JS_TOOLS = {
embed: Embed,
table: Table,
marker: Marker,
list: List,
warning: Warning,
code: Code,
linkTool: LinkTool,
image: Image,
raw: Raw,
header: Header,
quote: Quote,
checklist: CheckList,
delimiter: Delimiter,
inlineCode: InlineCode,
simpleImage: SimpleImage
};
return (
<EditorJs tools={EDITOR_JS_TOOLS} />
);
}
export default CustomEditor;
Then in your NextJS page, use a dynamic import like this:
let CustomEditor;
if (typeof window !== "undefined") {
CustomEditor = dynamic(() => import('../src/components/CustomEditor'));
}
And you can use your component:
return (
{CustomEditor && <CustomEditor />}
)
Source : https://github.com/Jungwoo-An/react-editor-js/issues/31
I am attempting to render playlist information for an Audio Player in React. The data is coming from a fetch call in the parent component (PostContent.js). The data being returned is an array of objects that looks like:
[ {name: ‘track name’, artist: ‘artist name’, url: ’https://blahblah.wav', lrc: ‘string’, theme: ‘another string’ }, {…}, {…}, etc. }
I am not able to return the data in the render() method of the child component (AudioPlayer.js). When I console.log(this.props.audio) in the render(), my terminal prints three responses. The first is an empty array, and the next two are the correct data that I need (an array of objects).
How can I set the props on the ‘audio’ key in the ‘props’ object in the render() method of the AudioPlayer.js component?
I should mention that I am using the react-aplayer library, and I am able to make this work with hard-coded data, as in the example here (https://github.com/MoePlayer/react-aplayer), but I am trying to make a dynamic playlist component for a blog website. Any advice is greatly appreciated.
AudioPlayer.js (Child Component)
import React, { PureComponent, Fragment } from 'react';
import ReactAplayer from '../react-aplayer';
import './AudioPlayer.css';
import sample from '../../src/adrian_trinkhaus.jpeg';
export default class AudioPlayer extends React.Component {
// event binding example
onPlay = () => {
console.log('on play');
};
onPause = () => {
console.log('on pause');
};
// example of access aplayer instance
onInit = ap => {
this.ap = ap;
};
render() {
console.log('props in render of AudioPlayer', this.props.audio)
const props = {
theme: '#F57F17',
lrcType: 3,
audio: this.props.audio
};
return (
<div>
<ReactAplayer
{...props}
onInit={this.onInit}
onPlay={this.onPlay}
onPause={this.onPause}
/>
</div>
);
}
}
PostContent.js (Parent Component)
import React, { Component, useState, Fragment } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import AudioPlayer from './AudioPlayer';
export default class PostContent extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
episodeData: [],
audio: []
}
}
async componentDidMount() {
const { id } = this.props.match.params;
const response = await fetch(`http://localhost:5000/episode/${id}/playlist`);
const jsonData = await response.json();
const songs = jsonData;
const audio = Object.keys(songs).map(key => {
return {
name: songs[key].name,
artist: songs[key].artist,
url: songs[key].url,
cover: songs[key].cover,
lrc: songs[key].lrc,
theme: songs[key].theme
}
});
this.setState({ audio })
}
componentDidUpdate(prevProps, prevState) {
if (prevState.audio !== this.state.audio) {
const newAudio = this.state.audio;
this.setState({ audio: newAudio }, () => console.log('new audio', this.state.audio))
}
}
render() {
return (
<Fragment>
<AudioPlayer audio={this.state.audio} />
<Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
{this.state.episodeData.map((item, i) => (
<div key={i} className="word-content">
<h2 className="show-title">{item.post_title}</h2>
<div className="episode-post-content">
<p>{item.post_content1}</p>
<p>{item.post_content2}</p>
<p>{item.post_content3}</p></div>
</div>
))}
<Table data={this.state.data} />
<div className="bottom-link">
<Link id='home-link' to='/' activeClassName='active'>Homepage</Link>
</div>
</Fragment>
)
}
}
i played around with an async scenario with your code on codesandbox
i think the problem is when you're trying to access the payload in ReactAPlayer component when audio it's not loaded yet from the async call. what you need to do is only use "audio" when it's valid like this if (audio.length) {...} or audio && ... some form of check to prevent it from being accessed in the reactAplayer render function.
fyi - you can remove the componentDidUpdate hook, since you have a setState call inside the ...Didmount hook, when setState is called inside ...didMount, the component calls its render() thus trigger a child re-render and its child will do the same..
Actually I think it doesnt work because you set this.props inside a props obejct, so maybe you need to do something like
var that = this
const props = {
audio = that.props.audio
}
I am trying to implement the plugins for the Filepond library for React.js using Firebase on the backend. The documentation is thin in regards to implementing the cropping plugin. All I want to do is force a 1:1 crop ratio on every image added as a profile picture, but with the current code, it is hanging at Waiting for size - Loading...
Mentioned in the docs here there is a hint at using transform plugin in conjunction to get the crop functionality, but not sure how to use the create() function to get this.
Is there any examples of implementing the crop to work as I intend? Or can someone show me how they got it to work? Thanks!
Code:
import React, { useState, Component } from "react";
// Filepond / Upload
import * as upload from "../../utils/upload";
import { FilePond, registerPlugin } from "react-filepond";
import "filepond/dist/filepond.min.css";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import FilePondPluginImageResize from "filepond-plugin-image-resize";
import FilePondPluginImageValidateSize from "filepond-plugin-image-validate-size";
import FilePondPluginFileValidateSize from "filepond-plugin-file-validate-size";
import "filepond/dist/filepond.min.css";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
import FilePondPluginImageTransform from "filepond-plugin-image-transform";
import FilePondPluginImageEdit from "filepond-plugin-image-edit";
registerPlugin(
FilePondPluginImageResize,
FilePondPluginImagePreview,
FilePondPluginImageValidateSize,
FilePondPluginFileValidateSize,
FilePondPluginImageTransform,
FilePondPluginImageEdit
);
export class Personal extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.updateProfPicUrl = this.updateProfPicUrl.bind(this);
this.user = this.props.user;
this.files = [];
this.pathToUrl = {};
this.basePath = `/users/${this.props.user.id}/images/profPic`;
this.process = upload.process(
this.basePath,
this.pond,
this.pathToUrl,
this.files
);
this.revert = upload.revert(this.pathToUrl, this.files);
}
updateProfPicUrl() {
if (this.files > 0) {
this.props.updateProfPicUrl(this.files, this.pathToUrl);
this.props.handleCloseModal();
} else {
alert("Please choose a file from your computer to upload first!");
}
this.files = [];
this.pathToUrl = {};
}
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
return (
<div>
<FilePond
ref={ref => (this.pond = ref)}
files={this.files}
allowMultiple={false}
imageEditInstantEdit={true}
imageCropAspectRatio={1}
onupdatefiles={fileItems => {
// Set current file objects to this.state
this.files = fileItems.map(function(fileItem) {
let file = fileItem;
file.uuid = uuid().toString();
return file;
});
}}
server={{
process: this.process,
revert: this.revert
}}
/>
<button
onClick={() => {
this.props.updateProfPicUrl(
this.files,
this.pathToUrl
);
}}
className="s-btn"
>
Update
</button>
</div>
);
}
}
Was finally able to revisit this, and I was able to easily do it. I did not need all the plugins, but just needed the ImageTransform and ImageCrop plugins. I just passed the properties:
allowImageCrop={true}
allowImageTransform={true}
imageCropAspectRatio={'1:1'}
to my <FilePond /> component. And imported:
import { FilePond, registerPlugin } from "react-filepond";
import "filepond/dist/filepond.min.css";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css";
import FilePondPluginImageCrop from 'filepond-plugin-image-crop'; // Crops image
import FilePondPluginImageTransform from 'filepond-plugin-image-transform'; // Changes image to match crop
registerPlugin(FilePondPluginImagePreview, FilePondPluginImageCrop, FilePondPluginImageTransform);
I'm have side bar navigation that get a list of json
import {
AppSidebarNav,
} from '#coreui/react';
<AppSidebarNav navConfig={navigation} {...this.props} />
and the data is the list of items
export default {
items: [
{
name: 'Dashboard',
url: '/dashboard',
icon: 'icon-speedometer',
},
{
name: 'Profile',
url: '/profile',
icon: 'icon-speedometer',
},...
],
};
how can I set the list of items before they load to the sidebar ?
there is any way to use componentDidMount()
to update the list ?
how should I approch this task
Put the list of items in its own file, say, nav.js. Then add this line to your imports
import navigation from "./nav"; // or whatever relative path nav.js is in.
You could use this sample code for fetch dynamic data by async, await and axios in AppSidebarNav core-ui
import React, {Component, Suspense} from "react";
import {
AppSidebarNav,
AppSidebar,
AppSidebarFooter,
AppSidebarForm,
AppSidebarHeader,
AppSidebarMinimizer,
} from "#coreui/react";
import axios from "axios";
import navigation from "../../_nav";
class SidebarNav extends Component {
constructor(props) {
super(props);
this.state = {
navData: null,
};
}
async getData() {
let res = await axios.get('REQUEST_URL');
this.setState({ navData: {items : res });
// OR // return await {items : res};
};
componentDidMount() {
if (!this.state.navData) {
(async () => {
try {
await this.getData();
// OR // this.setState({navData: await this.getData()});
} catch (e) {
//...handle the error...
console.log(e);
}
})();
}
}
render() {
return (
<AppSidebar fixed display="lg">
<AppSidebarHeader />
<AppSidebarForm />
<Suspense>
<AppSidebarNav navConfig={(this.state.navData === null) ? navigation : this.state.navData} {...this.props} />
</Suspense>
<AppSidebarFooter />
<AppSidebarMinimizer />
</AppSidebar>
)
}
}
export default SidebarNav;
}
navigation variable could be used for default data or loading...
export default {
items: [
{
name: 'Loading... ',
url: '/'
}
]
}
In the last part call SidebarNav Component in DefaultLayout or anywhere.
Old question, but for anyone wondering how to do this, I moved forward by doing the following:
Parent:
Setup constructor and added currentNavigation prop
Default new prop to default navigation
Change AppSidebarNav to use new prop
Create a function in the parent that takes a nav object, and updates the new currentNavigation prop
In this example, I add my navigation object to a property called index in a new object, this is required for the CoreUI nav it seems, however, you could do this in your child component / when creating the navigation object you will be using to update the menu.
/** Parent **/
import navigation from "../../navigation/_nav"
class DefaultLayout extends Component {
constructor(props) {
super(props)
this.currentNavigation = navigation //Set to default navigation from file
}
functionFromParent = (yourNavObject) => {
// nav contains the navigation object (build this however you do),
// but needs to be added to { items: ... }
let data = {
items: yourNavObject
}
this.currentNavigation = data;
}
render = () => {
return(
// ...More code
<AppSidebarNav
navConfig={this.currentNavigation} //Added function that child fires to prop
{...this.props}
router={router}
/>
// More code...
}
}
}
Child:
Get navigation object however you generate it to update the menu
Pass navigation object through to the functionFromParent using props (this.props.functionFromParent(this.getYourNavigationObject()))
/** Child **/
class ChildComponent extends Component {
// ... More Code
componentDidMount = () => {
let navigation = this.getYourNavigationObject() //Get your navigation object however you do
this.props.functionFromParent(navigation)
}
// More Code ...
}