React Typescript Video Preview - reactjs

I'm trying to create a video preview for a internal project, with "React & Typescript" using react hooks below is the component code,
import React, { useEffect, useRef, useState } from 'react';
import { INewVideo } from 'src/models';
import { useForm } from 'react-hook-form';
const NewVideo: React.FC = () => {
const { register, handleSubmit } = useForm<INewVideo>();
const [file, setFile] = useState<any>();
const videoChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
console.log(event.currentTarget.files![0]);
setFile(event.currentTarget.files![0])
};
useEffect(() => {
console.log("use effect", file)
}, [file])
return (<div>
<input
accept="video/mp4, video/mov"
onChange={videoChangeHandler}
type="file"
/>
{
file ? (
<div>
{file}
</div>
) : ("No Video")
}
</div>)
};
export default NewVideo;
But I'm not able to set the file, its throwing below error
I need to render upload video & give options for screen capture & trimming features. But these are later stages

You are getting this error because file is not a JSX.Element which you are trying to render in your DOM. Basically you got some Object in your file state. Either you can provide this as a source for HTML.Video Element or you can get file object data from it.
{
file ? <div> {file.name}</div> : "No Video";
}
This code should print the file name in your screen. This is the main place where you are getting some error.
Or if you want to show the preview of your recent upload video you can simply pass that file object as a HTML.Video src. Like it:
{
file ? <div> <video src={URL.createObjectURL(file)} autoPlay /></div> : "No Video";
}
This will show the preview of your video.

I've found below
import React, { useEffect, useState } from 'react';
import { INewVideo } from 'src/models';
import { useForm } from 'react-hook-form';
const NewVideo: React.FC = () => {
const { register } = useForm<INewVideo>();
const [file, setFile] = useState<any>();
const videoChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.currentTarget.files![0];
console.log("File", file);
const reader = new FileReader();
reader.addEventListener("load", () => {
setFile(reader.result);
});
reader.readAsDataURL(event.target.files![0]);
};
useEffect(() => {
console.log("use effect", file)
}, [file])
return (<div>
<input
{...register("Link")}
accept="video/mp4, video/mov"
onChange={videoChangeHandler}
type="file"
/>
<video controls src={file} />
</div>)
};
export default NewVideo;

Related

Local Image Upload Error in react-email-editor

I have integrated the react-email-editor into react, and when I upload an image from my local (size less than 500kb) It shows failed to upload image.
Please help, Below is the screen shot.
image
import { useRef, useState } from "react";
import EmailEditor from 'react-email-editor';
import sample from "./sample.json";
function App() {
const emailEditorRef = useRef(null);
const [json,SetJson]=useState();
const exportHtml = () => {
emailEditorRef.current.editor.exportHtml((data) => {
const { design, html } = data;
console.log('exportHtml', html);
console.log('design', design.body);
});
emailEditorRef.current.editor.saveDesign((design) => {
console.log("saveDesign", JSON.stringify(design, null, 4));
alert("Design JSON has been logged in your developer console.");
});
};
const onLoad = () => {
// editor instance is created
// you can load your template here;
const templateJson = sample;
emailEditorRef.current.editor.loadDesign(templateJson);
}
const onReady = () => {
// editor is ready
console.log('onReady');
};
return {
<div>
<div>
<button onClick={exportHtml}>Export HTML</button>
</div>
<div style={{width:"70vw"}}>
<EmailEditor ref={emailEditorRef} onLoad={onLoad} />
</div>
</div>
}
}
export default App;

React - context not updating

I am learning React by taking the implementation of reading a csv file, and breaking it into separate components that share data with context.
The problem is that after the user selects a file with FileSelector component, the state in ColumnsSelector is not updated, and file object (in ColumnSelector component) is still an empty object.
Thanks
Code:
FileSelector.jsx component gets the file from the user:
import React, { useContext } from "react";
import { DataContext } from './DataContext'
// Allowed extensions for input file
const allowedExtensions = ["csv"];
const FileSelector = () => {
const newError = useContext(DataContext).newError;
const changeFile = useContext(DataContext).changeFile;
const handleFileChange = (e) => {
if (e.target.files.length) {
const inputFile = e.target.files[0];
const fileExtension = inputFile?.type.split("/")[1];
if (!allowedExtensions.includes(fileExtension)) {
newError("Please input a csv file");
return;
}
changeFile(inputFile);
}
};
return (
<div>
<label htmlFor="csvInput" style={{ display: "block" }}>
Enter CSV File
</label>
<input
onChange={handleFileChange}
id="csvInput"
name="file"
type="File"
/>
</div>
);
};
export default FileSelector;
ColumnsSelector.jxs will be updated after the user selects a file, and will return the file headers:
import React, { useContext } from "react";
import Papa from "papaparse";
import { DataContext } from './DataContext'
// Allowed extensions for input file
const allowedExtensions = ["csv"];
const ColumnsSelector = () => {
const data = useContext(DataContext).data;
const changeData = useContext(DataContext).changeData;
const error = useContext(DataContext).error;
const newError = useContext(DataContext).newError;
const file = useContext(DataContext).file; // object is empty also after user uploads a file!
const handleParse = () => {
// If user clicks the parse button without
// a file we show a error
if (!file) return newError("Enter a valid file");
// Initialize a reader which allows user
// to read any file or blob.
const reader = new FileReader();
// Event listener on reader when the file
// loads, we parse it and set the data.
reader.onload = async ({ target }) => {
const csv = Papa.parse(target.result, { header: true });
const parsedData = csv?.data;
const columns = Object.keys(parsedData[0]);
changeData(columns);
};
reader.readAsText(file);
};
return (
<div>
<div>
<button onClick={handleParse}>Parse</button>
</div>
<div style={{ marginTop: "3rem" }}>
{Object.keys(data).length === 0 ? "" : data.map((col,
idx) => <div key={idx}>{col}</div>)}
</div>
</div>
);
};
export default ColumnsSelector;
DataSelector.jsx is a container for both components
import React, { useState } from "react";
import { DataProvider } from './DataContext'
import FileSelector from './FileSelector';
import ColumnsSelector from './ColumnsSelector'
// Allowed extensions for input file
const allowedExtensions = ["csv"];
const DataSelection = () => {
// This state will store the parsed data
const [data, setData] = useState([]);
// It state will contain the error when
// correct file extension is not used
const [error, setError] = useState(null);
// It will store the file uploaded by the user
const [file, setFile] = useState("");
const providerOptions = {
data: {},
changeData: (value) => setData(value),
error: {},
newError: (value) => setError(value),
file: {},
changeFile: (value) => setFile(value),
}
return (
<div>
<DataProvider value={providerOptions}>
<FileSelector />
<ColumnsSelector/>
</DataProvider>
</div>
);
};
export default DataSelection;
app.js holds DataSelector component:
import React from 'react';
import './App.css';
import DataSelector from './DataSelector';
function App() {
return (
<div className="App">
<header className="App-header">
<div>
<DataSelector />
</div>
</header>
</div>
);
}
export default App;
DataContext.js defined the context:
import React from 'react';
export const DataContext = React.createContext({});
export const DataProvider = DataContext.Provider;
export const DataConsumer = DataContext.Consumer;

onClickHandler sometimes work, sometimes not - React

The onClickHandler in the following code, in this component, 'SearchResult', sometimes work and sometimes not.
I can't figure out any logic that can explain why it works when it works, and why it's not working, when it's not working.
I've put a debugger inside the onClickHandler, at the beginning of it, and when it's not working, it doesn't get to the debugger at all - what indicates that the function sometimes isn't even called, and I can't figure out why.
Furthermore, I've tried to move all the code in function to the onClick, inline, but then, it's not working at all.
In addition, I've tried to use a function declaration instead of an arrow function, and it still behaves the same - sometimes it works, and sometimes it's not...
This is the site, you can see the behavior for yourself, in the search box.
This is the GitHub repository
Here you can see a video demonstrating how it's not working, except for one time it did work
Please help.
The problematic component:
import { useDispatch } from 'react-redux'
import { Col } from 'react-bootstrap'
import { getWeatherRequest } from '../redux/weather/weatherActions'
import { GENERAL_RESET } from '../redux/general/generalConstants'
const SearchResult = ({ Key, LocalizedName, setText }) => {
const dispatch = useDispatch()
const onClickHandler = () => {
dispatch({ type: GENERAL_RESET })
dispatch(
getWeatherRequest({
location: Key,
cityName: LocalizedName,
})
)
setText('')
}
return (
<Col className='suggestion' onClick={onClickHandler}>
{LocalizedName}
</Col>
)
}
export default SearchResult
This is the parent component:
import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Form } from 'react-bootstrap'
import { getAutoCompleteResultsRequest } from '../redux/autoComplete/autoCompleteActions'
import { AUTO_COMPLETE_RESET } from '../redux/autoComplete/autoCompleteConstants'
import SearchResult from './SearchResult'
const SearchBox = () => {
const [text, setText] = useState('')
const dispatch = useDispatch()
const autoComplete = useSelector((state) => state.autoComplete)
const { results } = autoComplete
const onChangeHandler = (e) => {
if (e.target.value === '') {
dispatch({ type: AUTO_COMPLETE_RESET })
setText('')
}
setText(e.target.value)
dispatch(getAutoCompleteResultsRequest(e.target.value))
}
const onBlurHandler = () => {
setTimeout(() => {
dispatch({ type: AUTO_COMPLETE_RESET })
setText('')
}, 100)
}
return (
<div className='search-box'>
<Form inline>
<div className='input-group search-md search-sm'>
<input
type='search'
name='q'
value={text}
onChange={onChangeHandler}
onBlur={onBlurHandler}
placeholder='Search Location...'
className='mr-sm-2 ml-sm-3 form-control'
/>
</div>
</Form>
<div className='search-results'>
{results &&
results.map((result) => {
return (
<SearchResult key={result.Key} {...result} setText={setText} />
)
})}
</div>
</div>
)
}
export default SearchBox
I played a bit with your code and it looks like a possible solution may be the following addition in the SearchResult.js:
const onClickHandler = (e) => {
e.preventDefault();
...
After some tests
Please remove the onBlurHandler. It seams to fire ahaed of the onClickHandler of the result.
Can you put console.log(e.target.value) inside the onChangeHandler,
press again search results and make sure that one of it doesn't working and show us the console.
In searchResult component print to the console LocalizedName as well

TypeScript Property 'value' does not exist on type 'HTMLElement'. React Jest Testing

Currently without TypeScript this code is working, but now it is not working unfortunately. It gave me the following error: Property 'value' does not exist on type 'HTMLElement'. Not sure what is wrong with this. Seems it is nagging about the value. In this case I am using Jest testing and React. Not sure if I can ignore this error or should fix this in order to avoid weird bugs in the future.
import React from 'react';
import axios from 'axios';
import { useDispatch } from "react-redux";
import { getData } from '../../../actions/index';;
export const SearchInput : React.FC = () => {
const dispatch = useDispatch();
let input: any;
const getInputValue = (value: string):void => {
let url = `https://api.tvmaze.com/search/shows?q=${value}`
}
return (
<div className="container">
<h1>Keyword</h1>
<form className="form display-inline-flex"
onSubmit={e => {
e.preventDefault()
if(!input.value.trim()) return;
getInputValue(input.value);
}}>
<input className="form-input-field disable-outline display-inline"
ref={node => (input = node)}
placeholder="Search catalog"
aria-label="search-input"
/>
<button type="submit" className="btn btn-grey white-color display-inline">
Search
</button>
</form>
</div>
)
}
export default SearchInput;
// Jest testing
import React from "react"
import { render, fireEvent } from "#testing-library/react";
import { SearchInput } from "./SearchInput";
import { Provider } from "react-redux";
import { store } from "../../../Store";
const setup = () => {
const utils = render(
<Provider store={store}>
<SearchInput/>
</Provider>);
const input = utils.getByLabelText("search-input");
return {
input,
...utils
}
}
test("It should check if input field get the value passed", () => {
const { input } = setup();
fireEvent.change(input, { target: { value: "search-bar-test" } })
expect(input.value).toBe("search-bar-test")
});
You should be good to go if you add a type assertion like:
const input = utils.getByLabelText("search-input") as HTMLInputElement;

Using Draft js mention plugin with react hooks

I have been trying to get draft js mention plugin to work with react hooks but can't seem to figure what's wrong with the code. Appreciate any help on this.
import React, { useRef, useState, useEffect } from "react";
import { EditorState } from "draft-js";
import Editor from "draft-js-plugins-editor";
import createMentionPlugin, { defaultSuggestionsFilter } from "draft-js-mention-plugin";
import mentions from "./mentions";
export default function MentionEditor() {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const [suggestions, setSuggestions] = useState(mentions);
const editor = useRef(null);
useEffect(() => {
editor.current.focus();
}, [])
const mentionPlugin = createMentionPlugin();
const { MentionSuggestions } = mentionPlugin;
const plugins = [mentionPlugin];
const onSearchChange = ({ value }) => {
setSuggestions(defaultSuggestionsFilter(value, mentions))
};
return (
<div style={{ border: "1px solid gray" }}>
<Editor
editorState={editorState}
onChange={editorState => setEditorState(editorState)}
plugins={plugins}
ref={editor}
/>
<MentionSuggestions
onSearchChange={onSearchChange}
suggestions={suggestions}
/>
</div>
);
}
You need to move the draft-js plugin configuration outside the component arrow function. This is a pretty basic Draft-JS implementation using a functional component and hooks:
import React, { useState, useRef } from 'react'
import { EditorState } from 'draft-js'
import Editor from 'draft-js-plugins-editor'
import createMentionPlugin, { defaultSuggestionsFilter } from 'draft-js-mention-plugin'
import 'draft-js/dist/Draft.css'
import 'draft-js-mention-plugin/lib/plugin.css'
import mentions from "./mentions"
// Draft-JS-Mentions plugin configuration
const mentionPlugin = createMentionPlugin()
const { MentionSuggestions } = mentionPlugin
const plugins = [mentionPlugin]
const MyEditor= () => {
const [suggestions, setSuggestions] = useState(mentions)
// Draft-JS editor configuration
const [editorState, setEditorState] = useState(
() => EditorState.createEmpty(),
)
const editor = useRef(null)
// Check editor text for mentions
const onSearchChange = ({ value }) => {
setSuggestions(defaultSuggestionsFilter(value, mentions))
}
const onAddMention = () => {
}
// Focus on editor window
const focusEditor = () => {
editor.current.focus()
}
return (
<div onClick={() => focusEditor()}>
<Editor
ref={editor}
editorState={editorState}
plugins={plugins}
onChange={editorState => setEditorState(editorState)}
placeholder={'Type here...'}
/>
<MentionSuggestions
onSearchChange={onSearchChange}
suggestions={suggestions}
onAddMention={onAddMention}
/>
</div>
)
}
export default MyEditor
Just move these lines outside component and it will work:
const mentionPlugin = createMentionPlugin();
const { MentionSuggestions } = mentionPlugin;
const plugins = [mentionPlugin];
export default function MentionEditor() {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
.. ... ...
}
!!!!!!!!!!!!!!!! PAY ATTENTION !!!!!!!!!!!!
The onSearchChange method will be triggered once the '#' character is typed, so in this case it will return just 5 items that fit the empty string...
To prevent this to be happened, just check that the value we want to search is not empty:
const onSearchChange = ({ value }) => {
if (value) {
setSuggestions(defaultSuggestionsFilter(value, mentions));
}
};

Resources