Implement Draft JS into Next JS, Text Editor Won't Show - reactjs

I am trying to implement draft js as text editor into my next.js project. I have implemented all code based on official guide but the text editor won't show. Here is my code
index.js
import React, { Component } from 'react'
import { useRouter, Router } from 'next/router';
import Layout from '../../components/MyLayout';
import Settings from '../../components/Settings';
import MyEditor from '../../components/TextEditor';
import fetch from 'isomorphic-unfetch';
import {Editor, EditorState} from 'draft-js';
const Post = (props) => {
const router = useRouter();
const object = props.post.data[0];
return (
<Layout>
<h1>{object.title}</h1>
<div className="p-2 border bg-light text-right text-dark">Oleh: {object.username}</div>
<MyEditor/>
</Layout>
);
}
Post.getInitialProps = async function(context) {
const {id} = context.query;
const FormData = new URLSearchParams();
FormData.append('slug',`${id}`);
const res = await fetch(Settings.api+'viewPost',{
'method': 'POST',
'body': FormData
});
const post = await res.json();
console.log('aw');
return {
post
};
};
export default Post;
TextEditor.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
export default function MyEditor() {
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
return (
<Editor
editorState={editorState}
onChange={setEditorState}
/>
);
}
I really appreciate any answer. Thank you

It looks like you're doing the right thing - Draft-js is very much a low-level editing tool that you can build rich text-editing on top of - I'm guessing that the editor is actually rendering on the page, but you haven't added any toolbars or complex initial state so you're just seeing a blank page.
I reproduced a super basic Next JS example here: https://codesandbox.io/s/naughty-swirles-7nmbf?file=/pages/index.js and you'll see that the editor itself is 'invisible' as there is no styling applied and no toolbar. If you look further into the Draft-js docs you'll see you can apply initial config objects that will give it a basic style (which you can further customize as you wish).

Related

Inserting Middleware(insights) with Instantsearch react

So, we have a functional search with Algolia/Instantsearch/React/Nextjs. But the Insights middleware is currently not setup.
Below is a trimmed version of the implementation, we use custom widgets to have more fine control over the display of results.
We use the hooks implementation for the custom widgets like so
const { hits, sendEvent, ... } = useInfiniteHits(props)
import { useState } from 'react'
import algoliasearch from 'algoliasearch/lite'
import { InstantSearch, InstantSearchSSRProvider } from 'react-instantsearch-hooks-web'
import SearchBox from '#components/swatches/algolia/SearchBox'
import Hits from '#components/swatches/algolia/Hits'
import RefinementList from '#components/swatches/algolia/RefinementList'
import CurrentRefinements from '#components/swatches/algolia/CurrentRefinements'
import { getServerState } from 'react-instantsearch-hooks-server'
import Container from 'react-bootstrap/Container'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import { history } from 'instantsearch.js/es/lib/routers/index.js'
import styles from '#styles/page.module.scss'
const Page = ({ serverState, url }) => {
const searchClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_INDEX_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
)
return (
<div className={styles.wrapper}>
<InstantSearchSSRProvider {...serverState}>
<InstantSearch
searchClient={searchClient}
indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX}
routing={{
router: history({
getLocation: () =>
typeof window === 'undefined' ? new URL(url) : window.location,
}),
}}
>
<Container fluid="lg">
<div className="mb-3">
<SearchBox />
</div>
<CurrentRefinements />
<Hits />
</Container>
</InstantSearch>
</InstantSearchSSRProvider>
</div>
)
}
export default Page
export async function getServerSideProps({ req, res, resolvedUrl}) {
const protocol = req.headers.referer?.split('://')[0] || 'https';
const url = `${protocol}://${req.headers.host}${req.url}`;
const serverState = await getServerState(<Page url={url} />);
return {
props: {
serverState,
url,
},
}
}
So my question is, where do we hook up the insights middleware for this specific implementation?
Reading the docs, (https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/) I'm not really 100% sure where to start. I can't find anywhere in the instantsearch react docs where it references anyway to configure that sort of thing.
Am I better of just firing events at the API directly instead of with InstantSearch?
Thanks
The trick is finding the InstantSearch instance using useInstantSearch:
const instantSearch = useInstantSearch();
instantSearch.use(middleware)
The docs should tell you what to do from there.

react-img-mapper blanck screen

I have a project where i need to map specific areas of an image, for that i'm trying to use react-img-mapper, but when i try to run the example code, the only think that shows is a blanck screen, react do not log any erros. What am i doing wrong ?
import React from 'react';
import ImageMapper from 'react-img-mapper';
const Mapper = props => {
const URL = 'https://raw.githubusercontent.com/img-mapper/react-docs/master/src/assets/example.jpg';
const MAP = {
name: 'my-map',
// GET JSON FROM BELOW URL AS AN EXAMPLE
areas: 'https://raw.githubusercontent.com/img-mapper/react-docs/master/src/assets/example.json',
};
return <ImageMapper src={URL} map={MAP} />
}
export default Mapper;

getting image from local storage using react

I am trying to work on a simple image editor using cropperjs and react, I want my project to let the user upload an image crop it and then download it I am using the browser local storage to store the user's image then I am importing the image from local storage to the canvas, if the user does not upload an image I have a default image to let the user play with.
The local storage is storing the user image properly and download is also working for me but my problem is that the local storage image is not coming to canvas and it shows only the default image.
here is my upload form component code
import React from 'react';
const UploadForm = ({uploader}) => {
const handleChange = (e) =>{
uploader(e.target.files[0])
}
return <form>
<input type="file" accept ="image/*" onChange ={handleChange}/>
</form>;
}
export default UploadForm;
and here is my App component code
import React, { useState, useEffect } from 'react';
import Cropper from './comps/cropper.jsx';
import UploadForm from './comps/UploadForm.jsx';
const App = () => {
const [url, setUrl] =useState('');
const uploader = (file) =>{
const reader = new FileReader();
reader.addEventListener('load', ()=>{
localStorage.setItem('recent-image',reader.result)
})
reader.readAsDataURL(file);
}
useEffect(() => {
setUrl(localStorage.getItem('recent-image'));
}, [])
return (
<div>
<UploadForm uploader = {uploader}/>
<Cropper src ={url}/>
</div>
);
}
export default App;
and here is my cropper component code
import React, { Component } from 'react'
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.min.css';
import './cropper.css'
import image from '../image.png';
export class cropper extends Component {
state= {
imageDestination:""
}
imageElement = React.createRef();
componentDidMount(){
const cropper = new Cropper(this.imageElement.current, {
// zoomable:true,
scalable:true,
aspectRatio:1,
crop:()=>{
const canvas = cropper.getCroppedCanvas();
this.setState({
imageDestination:canvas.toDataURL('image/png')
})
}
});
}
render() {
return (
<div>
<div className ="img-container">
<img ref ={this.imageElement} src ={this.props.src||image} alt ="source"/>
</div>
<img src = {this.state.imageDestination} className = "img-preview" alt ="Destination" />
{this.state.imageDestination&&<a href ={this.state.imageDestination}
download>Download</a>
}
</div>
)
}
}
export default cropper
in cropper.jsx, you export the class cropper and also export default cropper in the end of the file too.
export class cropper extends Component
export default cropper
Maybe that's what is causing the issue

Import image dynamically in React component

I have an Articles component that shows a blog page with listed articles.
render() {
const articles = {
...this.state.articles
}
const article = Object.keys(articles).map(cur => {
return <Article
key={this.state.articles[cur].id}
imgName={this.state.articles[cur].thumb}
title={this.state.articles[cur].title}
meta={this.state.articles[cur].meta}
clicked={() => this.detailedHandler(this.state.articles[cur].id)}
detailed={this.state.articles[cur].detailed} />
});
As you can see I pass image name with props to Article component.
I want then to display the appropriate image for each article.
How do I import an image in Article component based on the props I receive (props.imgName) from Articles component?
I used context.
const images = require.context('../../../assets/img', true);
loadImage = imageName => (assets(`./${imageName}`).default);
<img src={loadImage("someimage.png")} alt="" />
I don't know if this is an optimal solution, but it works.
You can load images dynamically from the API response with dynamic imports that is Stage 3 proposal as of now.
The resulting code should look something like:
loadImage = imageName => {
import(`./assets/${imageName}.jpg`).then(image => {
this.setState({
image
});
});
};
render() {
const { image } = this.state;
return (
<Fragment>
{image && <img src={image} alt="" />}
</Fragment>
);
}
View Codesandbox Demo
This feature is supported out of the box in create-react-app, If using other systems, you can use the Babel plugin
For anyone looking for a modern approach using async-await and custom react hooks, I found a pretty slick solution. Create a file called useImage.js and paste the following code:
import { useEffect, useState } from 'react'
const useImage = (fileName) => {
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [image, setImage] = useState(null)
useEffect(() => {
const fetchImage = async () => {
try {
const response = await import(`../assets/img/${fileName}`) // change relative path to suit your needs
setImage(response.default)
} catch (err) {
setError(err)
} finally {
setLoading(false)
}
}
fetchImage()
}, [fileName])
return {
loading,
error,
image,
}
}
export default useImage
Then just import the custom hook into your image component, mine looks something like this:
import useImage from '../../hooks/useImage'
import Typography from './Typography' // simple plain-text react component
const Image = ({ fileName, alt, className, ...rest }) => {
const { loading, error, image } = useImage(fileName)
if (error) return <Typography>{alt}</Typography>
return (
<>
{loading ? (
<Typography>loading</Typography>
) : (
<img
className={`Image${
className
? className.padStart(className.length + 1)
: ''
}`}
src={image}
alt={alt}
{...rest}
/>
)}
</>
)
}
export default Image
The nice thing about this solution is that no matter where your component is in relation to your assets folder, the react hook is always in the same place, so the relative path stays the same.
there are my way, works nicely:)
import React, {useState} from "react"
const getFavorites = (props) => {
const {item, favouritesNote} = props;
const [image, setImage] = useState("");
(function (imageName) {
import(
`../../../../assets/images/chart/favorite${imageName ? "_active" : ""}.png`
).then((image) => setImage(image.default));
})(favouritesNote[item.id]);
return (
<div>{image && <img alt="" className="img-responsive" src={image} />}</div
)
}
Note: All these comments work complementary with the #jadenRose hook solution which is a great abstraction.
You can import the images dynamically with the native js dynamic import('') , there's no need for React Lazy.
However, you have to be aware of the path/content you pass to the import(path) because depending on how you are planning to include the images to import in the final bundle there could be restrictions. There are two main ways:
Note: This is for Rollup, in Webpack i didn't try it but should be similar
a)- Making rollup automatically include the possibles files to import while creating the bundle using the official plugin https://www.npmjs.com/package/#rollup/plugin-dynamic-import-vars please read the doc and notice how there are important restrictions in the 'path' string, essentially you should just set the file name in the variable, the rest of the path have to be fixed in the import('') in order to provide rollup a restricted scope to import. eg:
OK
import(../assets/img/${fileName}.svg)
Wrong
import(filePath)
b)- Include in the bundle programmatically the files you can dynamically import example
//rollup.config.js
import copy from 'rollup-plugin-copy';
plugins: [
copy({
targets: [ { src: 'src/assets/icons/*', dest: 'lib/assets/icons' },],
}),
…
],
With this option b) you have no restrictions on the variable content but have to be careful with what you included in the bundle.
Conclusion: You can use dynamic import(...) but if you not properly handle the files inclusion on the bundle, it can be possible they are excluded and then the dynamic import will fail in the consumer.
I found this worked best for me:
I created an index file inside the images folder. there I imported all the images I have and created a class component with the variables assigned to each image import. this is because when we import an image in react using the import statement, that is, import someImage from './somewhere' react assigns the 'someImage' variable to a module with a 'static media' address, my terminology there might be wrong. Here is the example:
import image13_1 from './image13_1.png';
import image13_2 from './image13_2.png';
import image13_3 from './image13_3.png';
import image13_4 from './image13_4.png';
import image13_5 from './image13_5.png';
import image13_6 from './image13_6.png';
import image13_7 from './image13_7.png';
export class IMG{
1= image13_1
2 = image13_2
3 = image13_3
4 = image13_4
5 = image13_5
6 = image13_6
7 = image13_7
}
export default IMG;
from here I just import the IMG class and create an instance of it and call the image number a property:
var img = new IMG()
console.log('img',img[1]

Code Mirror will not function in my React application

I am attempting to create a Web IDE sort of like Eclipse Orion. The code editor that I plan to use is Code Mirror; the only difficulty is that I cannot get the code editor to load. Here is the error that I am encountering.
Here is the code that got me to this issue.
import React, { Component } from 'react';
import codemirror from 'codemirror';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/monokai.css';
class Editor extends Component {
componentDidMount = () => {
this.codeMirror = codemirror.fromTextArea(this.codeEditor, {
mode: 'markdown'
});
};
codeEditor = React.createRef();
render = () => (
<div>
<textarea ref={this.codeEditor} />
</div>
);
}
export default Editor;
This issue has been stated many times here, but with no solution that made sense in my situation. Thanks in advance.
This code seemed to do the trick, it was just an issue with the ref.
import React, { Component } from 'react';
import codemirror from 'codemirror';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/lib/codemirror.css';
class Editor extends Component {
componentDidMount = () => {
this.codeMirror = codemirror(this.editor, {
mode: 'markdown'
});
};
ref = React.createRef();
render = () => (
<div>
<div ref={self => this.editor = self} />
</div>
);
}
export default Editor;

Resources