Electron cannot read property 'path' of undefined videos I have uploaded - javascript

I am trying to convert a video that I have successfully loaded up to an Electron with React project. I did not have a problem adding the videos, but when I try to convert the video to a different file type I get the error below:
Uncaught Exception: TypeError: Cannot read property 'path' of
undefined
at EventEmitter.ipcMain.on (/Users/danale/Projects/ElectronCode/boilerplates/convert/index.js:37:32)
at emitTwo (events.js:106:13)
at EventEmitter.emit (events.js:191:7)
at WebContents. (/Users/danale/Projects/ElectronCode/boilerplates/convert/node_modules/electron/dist/Electron.app/Contents/Resources/electron.asar/browser/api/web-contents.js:247:37)
at emitTwo (events.js:106:13)
at WebContents.emit (events.js:191:7)
Its referencing this code below:
ipcMain.on("conversion:start", (event, videos) => {
const video = videos[0];
const outputDirectory = video.path.split(video.name)[0];
const outputName = video.name.split(".")[0];
const outputPath = `${outputDirectory}${outputName}.${video.format}`;
console.log(outputPath);
// ffmpeg(video.path).output();
});
but I do not see anything wrong with the code. Why is videos undefined now? I have been able to add them successfully.
Here is my action creator:
export const convertVideos = videos => (dispatch, getState) => {
ipcRenderer.send("conversion:start", videos);
};
This is my reducer:
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case VIDEO_COMPLETE:
return { ...state, [action.payload.path]: { ...action.payload, complete: true } };
case VIDEO_PROGRESS:
return { ...state, [action.payload.path]: action.payload };
case ADD_VIDEOS:
return { ...state, ..._.mapKeys(action.payload, 'path')}
case ADD_VIDEO:
return { ...state, [action.payload.path]: action.payload };
case REMOVE_VIDEO:
return _.omit(state, action.payload.path);
case REMOVE_ALL_VIDEOS:
return INITIAL_STATE
default:
return state;
}
}
convertVideos is being called from src/components/ConvertPanel.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router'
import * as actions from '../actions';
class ConvertPanel extends Component {
onCancelPressed = () => {
this.props.removeAllVideos();
this.props.history.push('/')
}
render() {
return (
<div className="convert-panel">
<button className="btn red" onClick={this.onCancelPressed}>
Cancel
</button>
<button className="btn" onClick={this.props.convertVideos}>
Convert!
</button>
</div>
);
};
}
export default withRouter(
connect(null, actions)(ConvertPanel)
);

So when DanStarns asked for me to show where convertVideos is being called and I posted the ConvertPanel.js file, I felt something was amiss there, this did not seem right:
export default withRouter(
connect(null, actions)(ConvertPanel)
);
No need for a mapStateToProps there? The videos object was defined when adding videos but it was not being set right by the Redux back-end when it came time to convert the file type of said object.
So for the convert button I decided to use an arrow function and then passed convertVideos the videos prop. That in itself was not enough and I believed I also needed a mapStateToProps and after lots of painful wrangling, this is what I came up with that worked:
render() {
return (
<div className="convert-panel">
<button className="btn red" onClick={this.onCancelPressed}>
Cancel
</button>
<button
className="btn"
onClick={() => this.props.convertVideos(this.props.videos)}
>
Convert!
</button>
</div>
);
}
}
const mapStateToProps = state => {
return { videos: _.at(state.videos, _.keys(state.videos)) };
};
export default withRouter(
connect(
mapStateToProps,
actions
)(ConvertPanel)
);
For the above to work I had to import lodash library and I do not like the way that mapStateToProps looks, if anyone has a more elegant version, I would be willing to adopt it.

Related

Minified React error #31 with sharepoint online using React + redux

I'm facing an error that has been searching by myself for 2 days. But currently It's still not resolved, so I came here to ask If anyone ever faced this?
I'm using Redux toolkit in a sharepoint online project for passing data to each other components.
The first component worked perfectly, but when I use useSelector function for the 2nd one, this error appears
Although when I tried using console.log for each component, both are still receiving the data but
using data for the 2nd component will happen this error.
So has anyone ever faced this please help me out~, here is my codes
slice:
import { createSlice } from '#reduxjs/toolkit';
export interface titleState {
title: string;
}
const initialState: titleState = {
title : 'Your title'
};
export const titleSlice = createSlice({
name: 'title',
initialState,
reducers: {
SET_TITLE: (state, action) => {
state.title = action.payload;
}
}
});
export const { SET_TITLE } = titleSlice.actions;
export default titleSlice.reducer;
store
import { configureStore } from '#reduxjs/toolkit';
import titleReducer from "../features/titleSlice/titleSlice";
export const store: any = configureStore({
reducer: {
title: titleReducer
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
first component:
import { useSelector, useDispatch } from "react-redux";
import { AppDispatch, RootState } from "../../../../redux/store/store";
const FirstComponent: FunctionComponent<FirstComponent> = (
props
) => {
const STATE_TITLE = useSelector((state: RootState) => state.title);
console.log(STATE_TITLE);
const dispatch = useDispatch<AppDispatch>();
const handleTitle = (e) => {
dispatch(SET_TITLE(e.target.value));
setTitle(e.target.value);
}
return (
<div>
<textarea
onChange={handleTitle} //works fine
/>
</div>
}
second component:
import { useSelector, useDispatch } from "react-redux";
import { AppDispatch, RootState } from "../../../../redux/store/store";
const SecondComponent: FunctionComponent<ISecondComponentProps> = (props) => {
const TITLE_STATE = useSelector((state: RootState) => state.title)
console.log(TITLE_STATE)
return (
<div>
{YOUR_TITLE} //this line happens error
</div>
)
and here is the error from development tab :
The error happens because your TITLE_STATE is an object and not a string. Try changing the return statement of the second component to
<div>
{TITLE_STATE?.title}
</div>
If this works, the error was because you were trying to render objects directly. And investigate why your textarea component returns an object instead of string as value, since that is the root cause here

React-Redux: Action Dispatch on button click not working

On click of Button my Action is not getting dispatched. Below are all the files viz - action, reducer, root reducer, configSTore, Index and Component.
Please help me why my action is not getting dispatched on button click
Actions.js
import axios from 'axios';
const requestURL='JSONUrl';
let responseData = '';
export function fetchRequests() {
axios.get(requestURL)
.then((res) => {
responseData = res;
});
return responseData;
}
export const fetchDataAction = () => {
return {
type: 'FETCH_DATA',
data: fetchRequests()
};
}
export function fetchDataSuccessAction(err) {
return {
type: 'FETCH_DATA_SUCCESS',
err
};
}
export function fetchDataErrorAction(err) {
return {
type: 'FETCH_DATA_ERROR',
err
};
}
Reducer.js
export function fetchDataReducer(state = [], action) {
switch(action.type) {
case 'FETCH_DATA':
return action.data;
default: return state;
}
}
export function fetchDataSuccessReducer(state = [], action) {
switch(action.type) {
case 'FETCH_DATA_SUCCESS':
return action.err;
default: return state;
}
}
export function fetchDataErrorReducer(state = [], action) {
switch(action.type) {
case 'FETCH_DATA_ERROR':
return action.err;
default: return state;
}
}
RootReducer
import {combineReducers} from 'redux';
import { fetchDataAction, fetchDataSuccessAction, fetchDataErrorAction}
from '../actions/fetchData';
export default combineReducers({
fetchDataAction,
fetchDataSuccessAction,
fetchDataErrorAction
});
configStore.js
import { createStore, applyMiddleware } from "redux";
import rootReducer from "../reducers/rootReducer";
import thunk from 'redux-thunk';
export default function configureStore() {
const enhance = applyMiddleware(thunk);
return createStore(
rootReducer,
enhance
);
}
INdex.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
import Header from './App';
import configureStore from './store/configureSTore';
import {CounterApp} from './counter';
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={configureStore()}>
<Header favcol="yellow"/>
<CounterApp />
</Provider>,
document.getElementById('root')
);
reportWebVitals();
My Component File
import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';
export class CounterApp extends React.Component {
constructor(props) {
super(props);
}
btnClick = () => {
return this.props.fetchDataAction;
}
render() {
return (
<div className="App">
<h1>Hello</h1>
<div>
<h1>Fetch Data click below</h1>
<button onClick={() => this.props.fetchDataAction}>
Fetch Data
</button>
{this.props.datafetchedFromApi}
</div>
</div>
)
}
}
const mapStateToProps = state => ({
datafetchedFromApi: state.data
});
const mapDispatchToProps = (dispatch) => ({
fetchDataAction: () => dispatch(fetchDataAction())
});
export default connect(mapStateToProps, mapDispatchToProps)(CounterApp);
On click of Button my Action is not getting dispatched. Below are all the files viz - action, reducer, root reducer, configSTore, Index and Component.
Please help me why my action is not getting dispatched on button click
The answer got too long, so first part is if you wanna fully understand why things went south. If you just want your problem solved so you can finally go pee, the second part is for you :).
First Part (Basically what asynchronous programming in JavaScript is, so any questions to what are asynchronous tasks in JS can be referred to this answer.)
Okay a couple of problems detected here. As others have pointed out make sure all the paths for imports are correct. Now assuming they are all correct, here's what you need to do to solve your problem.
First let's take a look at the top of your component file:
import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';
...
And then the block where you have called fetchDataAction:
...
<button onClick={() => this.props.fetchDataAction}>
Fetch Data
</button>
...
Here what you have done is this.props.fetchDataAction, I don't see you passing fetchDataAction as a prop to this component, so it's most probably undefined that's why you get an error TypeError: this.props.fetchDataAction is not a function because of course undefined is not a function.
This was the first mistake I noticed.
Now, moving on to the second one. I'm gonna start with this
Dispatching actions in redux is synchronous.
So you cannot do something like the following:
export default function SomeComponent(props) {
const fetchAction = () => {
let payload;
//wait for 5 seconds for the async task(the setTimeout below is an async task) to populate the payload with data.
setTimeout(() => payload = "This is my data", 5000);
//then return the action object
return {
type: 'Data',
payload,
};
}
const handleClick = () => {
dispatch(fetchAction());
}
return (<>
<Button onClick={handleClick} />
</>);
}
The above will not throw any errors, but will certainly not do what I want it to do. The above will dispatch the following action object:
{
type: 'Data',
payload: undefined
}
which ofcourse is not what I want the payload to be.
And that's exactly what you're doing. Take a look at your fetchDataAction and fetchRequests functions:
...
let responseData = '';
export function fetchRequests() {
axios.get(requestURL)
.then((res) => {
responseData = res;
});
return responseData;
}
export const fetchDataAction = () => {
return {
type: 'FETCH_DATA',
data: fetchRequests()
};
}
...
Now I'll compare with the example I've given above:
Here your responseData is analogous to my payload
Your fetchRequests function is analogous to my setTimeout
Looks familiar? I'm sure by now it does. Plain simple answer as to why it doesn't work is that you're performing an async task, in your case you're making a network request with axios.get(requestUrl)...
Network requests are async(now if you don't know what async things are, check out https://javascript.info/callbacks which gives you idea about what those are. Also check out a video on it by TheNetNinja https://www.youtube.com/watch?v=ZcQyJ-gxke0 ), in simple words, \network requests take some time to get finished(just like setTimeout).
So the axios.get request takes some time to get the response back from the server. Now the other tasks(below it) won't wait for that request to get completed, instead js will execute those tasks immediately without waiting for the response.
I know this answer is getting too long. But I want you to understand, because trust me I have made the same mistakes before :).
So in your fetchRequests function:
export function fetchRequests() {
axios.get(requestURL) --- (1)
.then((res) => {
responseData = res; --- (2)
});
return responseData; --- (3)
}
In line 1, you start an async task. Remember the function inside then block will execute only after sometime. So the responseData is still undefined. Instead of line (2), line (3) will execute first, cause as I told you earlier, js won't wait for the response from the server(the technical wording is 'the thread doesn't get blocked by network request'.) So basically you're returning undefined from this function.
Also see this video by JavaBrains. He uses an excellent analogy to understand async tasks in js, and you might also learn about what the event loop is and about single threaded-ness of javascript.
https://www.youtube.com/watch?v=EI7sN1dDwcY
Now the Second part (I really wanna go pee):
Replace(I've pointed out where I have made changes)
Your component file with this.
import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';
export class CounterApp extends React.Component {
constructor(props) {
super(props);
}
btnClick = () => {
return this.props.fetchDataAction;
}
render() {
return (
<div className="App">
<h1>Hello</h1>
<div>
<h1>Fetch Data click below</h1>
<button onClick={() => fetchDataAction()}> //this is the only change here
Fetch Data
</button>
{this.props.datafetchedFromApi}
</div>
</div>
)
}
}
const mapStateToProps = state => ({
datafetchedFromApi: state.data
});
const mapDispatchToProps = (dispatch) => ({
fetchDataAction: () => dispatch(fetchDataAction())
});
export default connect(mapStateToProps, mapDispatchToProps)(CounterApp);
And then in your action.js file:
import axios from 'axios';
const requestURL='JSONUrl';
let responseData = '';
export function fetchRequests() {
return axios.get(requestURL) //change is here
//removed return responseData and the 'then' block
}
export const fetchDataAction = () => {
return dispatch => { //almost whole of this function is changed and that's it
fetchRequests().then((res) => {
responseData = res;
dispatch({
type: 'FETCH_DATA',
data: responseData
})
});
};
}
export function fetchDataSuccessAction(err) {
return {
type: 'FETCH_DATA_SUCCESS',
err
};
}
export function fetchDataErrorAction(err) {
return {
type: 'FETCH_DATA_ERROR',
err
};
}
Now it should work. Tell me more if it doesn't. Remember this answer is assuming that you have all your functions imported properly into your files. I'll be making edits if this doesn't answer your question.
So the answer was to use 'thunk' - an official "async function middleware" for redux.
Also see this to learn more about handling 'async actions' and also using redux thunk:
https://redux.js.org/tutorials/fundamentals/part-6-async-logic
https://www.npmjs.com/package/redux-thunk
Try this
<button onClick={() => this.props.fetchDataAction()}>
Also if you need to dispatch the url from your components you can do this way
<button onClick={() => this.props.fetchDataAction(url)}>
const mapDispatchToProps = (dispatch) => {
return {
fetchDataAction: (url) => dispatch(fetchRequests(url))
};
};
And in Action.js
export function fetchRequests(url) {
axios.get(url)
.then((res) => {
responseData = res;
});
return responseData;
}
<button onClick={() => this.props.fetchDataAction()}>
<button onClick={() => this.props.fetchDataAction}>
Here you are trying to return the function definition alone ,not call the fetchDataAction onclick use onClick={() => this.props.fetchDataAction()} or pass a separate handler for the onclick as good practice.
For the other issue you have mentioned TypeError: this.props.fetchDataAction is not a function is because of the curly brackets used while importing fetchRequests
Remove the curly brackets
import fetchRequests from "./actions/fetchData";
This should resolve your issue

When Using Redux Saga with React Get This Error .. Uncaught TypeError: getPosts is not a function

Trying to learn how to use Redux Sagas with React. Put together a simple example but it is not working for me.
My code in my App.js file:
const sagaMiddleware = createSagaMiddleWare();
const store = createStore(
reducers,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga);
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
Action Creator:
export const getPosts = () => {
return {
type: 'GET_POSTS'
}
};
Reducer:
const combineReducers = (state= {}, action) => {
switch (action.type) {
case 'GET_POSTS':
return { ...state, loading: true};
default:
return state;
}
}
export default combineReducers;
My Button component where the action should be called onClick
const ButtonContainer = (getPosts) => (
<button onClick={() => getPosts()}>Get Posts</button>
)
const mapDispatchToProps = {
getPosts: getPosts
}
export default connect(null, mapDispatchToProps)(ButtonContainer);
Problem is I get this error on page load.
Uncaught TypeError: getPosts is not a function....
Makes sense what the error is saying, it is getting the object instead of the function but not really sure what I need to do for this to work.
Thank you!
The code you have currently is not actually dispatching the getPosts action to your reducer.
Change you mapDispatchToProps to:
const mapDispatchToProps = dispatch => {
getPosts: bindActionCreators(getPosts, dispatch)
}
You'll also need:
import { bindActionCreators, Dispatch } from "redux"
Also change your ButtonContainer to:
const ButtonContainer = props => (
<button onClick={() => props.getPosts()}>Get Posts</button>
)
More info on dispatching can be found in this good documentation.

Redux is changing state of component and then it turns back to initial state

I am new Redux developer. I am trying to create a tab component using React and Redux in a web application.
When I select a tab I can in the console and in Redux Dev Tool that the state is changed, but as soon it changes it turns back to initial state (it happens to '' or 'tabData' or 'tabBulletin' in tabReducer.js
I don't understand it to solve this logical issue. Please, could anyone help me get wiser on this?
Thank you.
This is the parent React Tags related to the issue
<TabsHeader>
<TabHeader id='tab1-tab' label='Data | 34' target='tabData' />
<TabHeader id='tab2-tab' label='Bulletins | 35' target='tabBulletin' />
</TabsHeader>
<TabsContent>
</TabsContent>
TabHeader.js
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { selectTab } from './tabActions'
class TabHeader extends Component {
render() {
const selected = this.props.tab.selected === this.props.target
return (
<a href='/' id={this.props.id}
onClick={() => this.props.selectTab(this.props.target)}
data-target={this.props.target}
className={selected ? 'active' : '' }
>
{this.props.label}
</a>
)
}
}
const mapStateToProps = state => ({ tab: state.tab })
const mapDispatchToProps = dispatch => bindActionCreators({ selectTab },
dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(TabHeader)
tabActions.js
export function selectTab(tabId) {
console.log(tabId)
return {
type: 'TAB_SELECTED',
payload: tabId
}
}
tabReducer.js
const INITIAL_STATE = { selected: 'tabData' }
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'TAB_SELECTED':
return { ...state, selected: action.payload }
default:
return state
}
}
You dispatched wrong way. Where did you read this ?
dispatch => bindActionCreators({ selectTab }, dispatch)
All you need is just a simple dispatch like this:
dispatch => ({ selectTab: tabId => selectTab(tabId) })
That's is.
I am back again and now with the solution:
The problem is here on the tag of the component in TabHeader.js:
This makes the site to be reloaded turn it to initial state
So I changed to "javaxritp:;" which solves the issue with Redux.
The line below is to map action creators that allows to be trigged to send to reducers to develop state. I may loosing a small thing that makes Redux turn it back to initial state. I learnt that from my React class. Thank you anyway.
const mapDispatchToProps = dispatch => bindActionCreators({ selectTab }, dispatch)
dispatch => bindActionCreators({ selectTab }, dispatch)

React, TypeError (this.props.data.map is not a function) on an Array obj

Thank you for stopping by to help. I am working with a react/redux app. One of the component is using a lifecyle method to retrieve data from an API. Once recieved, the data JSON data is held within an array. My initialState for the data coming back is an empty array.
When the component listening to the state change is mounted, the data is rendered on to the page, but then 2 seconds later I am getting a
Uncaught TypeError: jobs.map is not a function
Component making the API call using lifecyle method and listening for state change
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getJobs } from '../../actions';
import { Card, Grid, Image, Feed } from 'semantic-ui-react';
// import './home.css';
const renderJobs = jobs => jobs.map((job, i) => (
<Card.Group stackable key={i}>
<Card className="jobscard">
<Card.Content>
<Card.Header href={job.detailUrl} target="_blank">{job.jobTitle}</Card.Header>
<Card.Meta>{job.location}</Card.Meta>
<Card.Description>{job.company}</Card.Description>
</Card.Content>
</Card>
</Card.Group>
));
class GetJobs extends Component {
componentDidMount() {
this.props.getJobs();
}
render() {
const { jobs } = this.props;
return (
<div className="getjobs">
{renderJobs(jobs)}
</div>
);
}
}
export default connect(({ jobs }) => ({ jobs }), { getJobs })(GetJobs);
Action creator/action
export const getJobsRequest = () => fetch('https://shielded-brushlands-43810.herokuapp.com/jobs',
)
.then(res => res.json());
// action creator
export const getJobs = () => ({
type: 'GET_JOBS',
payload: getJobsRequest(),
});
Reducer
import initialState from './initialState';
export default function (jobs = initialState.jobs, action) {
switch (action.type) {
case 'GET_JOBS_PENDING':
return { ...jobs, isFetching: true };
case 'GET_JOBS_FULFILLED':
return action.payload;
case 'GET_JOBS_REJECTED':
return jobs;
default:
return jobs;
}
}
And intial state
export default {
userData: {},
jobs: [],
}
enter image description here
any thoughts on why this is happening?
You can put a simple check to ensure that your jobs is ready before you attempt rendering it.
{jobs.length && renderJobs(jobs)}

Categories