I am building out an electron app with React and trying to use Material-UI for the UI elements. I added a datepicker and timepicker to a component and the input shows up in the electron app, however when you click on it, nothing happens. Not sure what I'm missing in order to get this to work correctly
Component :
import React, { Component } from 'react';
import DatePicker from 'material-ui/DatePicker';
import TimePicker from 'material-ui/TimePicker';
export default class Schedule extends Component {
render() {
return (
<div>
Pick a date :
<DatePicker id="date"/>
and time :
<TimePicker id="time"/>
</div>
)
}
}
index.js :
import 'babel-polyfill'; // generators
import React from 'react';
import { render as renderReact } from 'react-dom';
import debounce from 'debounce';
import configureStore from './store/configureStore';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
const state = JSON.parse(localStorage.getItem('state'));
const store = configureStore(state || {});
let App = require('./components/app').default;
const render = (Component) => {
renderReact(<MuiThemeProvider><Component {...store} /></MuiThemeProvider>, document.getElementById('root'));
};
if (module.hot) {
module.hot.accept('./components/app', function() {
let newApp = require('./components/app').default;
render(newApp);
});
}
const saveState = debounce(() => {
localStorage.setItem('state', JSON.stringify(store.getState()));
}, 1000);
store.subscribe(() => {
saveState();
render(App);
if (process.env.ENV === 'development') {
console.log('state', store.getState());
}
});
store.dispatch({ type: 'APP_INIT', store });
In your app.js, you need to import and execute the following plugin:
const injectTapEventPlugin = require('react-tap-event-plugin');
injectTapEventPlugin();
Related
I try to test my React app with Jest.
I have a button that copies text to the clipboard. (this text is generated in my App, the user can't see it on the screen)
I want to test this copied text with reference text. How can I get copied text from the clipboard in my test?
React component:
import React from 'react';
import { useSelector } from 'react-redux';
import useClipboard from 'react-use-clipboard';
function FileLoader() {
const state = useSelector((state) => state);
const dataForHtml = `<img src="${state.png}" alt="banner" />`;
const [isCopiedHtml, setCopiedHtml] = useClipboard(dataForHtml);
return (
<button className="btn" onClick={setCopiedHtml}>
Save
</button>
);
}
export default FileLoader;
The beginning of my test:
import { render, screen } from '#testing-library/react';
import React from 'react';
import userEvent from '#testing-library/user-event';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import FileLoader from '../src/components/FileLoader/FileLoader';
describe('save btns', () => {
const initialState = {
png: 'some_img_url'
},
const mockStore = configureStore()
let store
it('should save html', () => {
store = mockStore(initialState)
const { getByText } = render(<Provider store={store}><FileLoader /></Provider>)
const saveHtmlBtn = screen.findByText('html');
saveHtmlBtn.then((save) => {
userEvent.click(save)
});
})
})
I have created a small application and connected it to Redux. Unfortunately when creating new components and using the same exact code those new components cannot seem to connect to redux and get undefined when accessing it (using mapStateToProps).
I have tried to create new Components and connect them again to no avail. I'm kind of at loss as to why it isn't working especially since the rest of the application can connect and get the state properly
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store} >
<App />
</Provider>
, document.getElementById('root'));
store.js:
const initialState = {
guessedTimezone: '',
timezone: '',
pseudo: '',
};
function rootReducer(state = initialState, action) {
console.log(action);
if (action.type === 'CHANGE_TIMEZONE') {
return Object.assign({}, state, {
timezone: action.timezone,
guessedTimezone: action.guessedTimezone
})
}
if (action.type === 'CHANGE_PSEUDO') {
return Object.assign({}, state, {
pseudo: action.pseudo,
token: action.token
})
}
return state;
}
export default rootReducer;
new Component not connecting:
import React, { Component } from 'react'
import { connect } from 'react-redux'
export class TestPseudo extends Component {
render() {
console.log(this.props.pseudo);
return (
<div>
{this.props.pseudo}
</div>
)
}
}
const mapStateToProps = state => {
return {
pseudo: state.pseudo
}
}
export default connect(mapStateToProps)(TestPseudo)
Here for example this.props.pseudo returns undefined when, if the connection happens, it should return the value if i understand it correctly and yet it shows undefined
EDIT:
App.js as per requested :
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Homepage from './Components/Homepage';
import moment from 'moment';
import moment_timezone from 'moment-timezone';
import HeaderApp from './Components/HeaderApp';
import { TestPseudo } from './Components/TestPseudo';
export class App extends Component {
async componentDidMount() {
let tz = moment.tz.guess(true);
let date = moment(new Date()).local();
let timezone = date['_i'].toString().split('(')[1].split(')')[0];
this.props.dispatch({
type: 'CHANGE_TIMEZONE',
guessedTimezone: tz,
timezone: timezone
})
console.log(`Guessed timezone: ${tz} (${timezone})`);
}
_showHomepage() {
if (this.props.showHomepage && this.props.loaded) {
return (
<div style={styles.mainWindow}>
{/*<Homepage click={this._handleClick} />*/}
<TestPseudo />
</div>
)
}
}
_showHeader() {
return (
<div>
<HeaderApp />
</div>
)
}
render() {
return (
<div>
{this._showHeader()}
{this._showHomepage()}
</div>
)
}
}
const styles = {
mainWindow: {
height: '100vh',
width: '100vw'
}
}
const mapStateToProps = state => {
return {
guessedTimezone: state.guessedTimezone,
timezone: state.timezone,
};
};
export default connect(mapStateToProps)(App);
I call that new Component instead of my old Component. The homepage can connect but not the new one so i think it's not a problem of emplacement
I think its here
import { TestPseudo } from './Components/TestPseudo';
You are importing the non-connected component. Try this
import TestPseudo from './Components/TestPseudo';
For your understanding, exporting as default can be imported like so;
export default Component
import WhateverName from ....
Named export like const or in your case class;
export class Component
import { Component } from ...
So use brackets when Named, and skip brackets when default.
I'm trying to toggle my modal via redux but for some reason I'm getting an error that says: TypeError: Cannot read property 'isModalOpen' of undefined (pointing to the line isOpen: state.global.isModalOpen inside List.js) which means my root reducer isn't defined properly. But I'm sure I've defined it properly inside index.js file. What am I doing wrong and how would I be able to resolve this and use these actiontypes properly in order for it to work?
Note: The <Modal/> component is an npm package I installed, I didn't create it on my own.
Here's my List.js file:
import React, { Component } from 'react';
import Aux from '../../../../hoc/Aux';
import { connect } from 'react-redux';
import Modal from 'react-modal';
class List extends Component {
state = {
isOpen: false
}
componentWillMount() {
Modal.setAppElement('body');
}
toggleModal = () => {
this.setState({isActive:!this.state.isActive});
}
closeModal = () => {
this.setState({isActive: false});
}
render() {
return (
<Aux>
<CheckoutButton clicked={this.toggleModal}/>
<Modal isOpen={this.state.isOpen}>
<button onClick={this.closeModal}>Close</button>
</Modal>
</Aux>
);
}
}
const mapStateToProps = state => {
return {
isOpen: state.global.isModalOpen
}
};
const mapDispatchToProps = dispatch => {
return {
closeModalRedux: () => dispatch({type: CLOSE_MODAL})
}
};
export default connect(mapStateToProps, mapDispatchToProps)(List);
Here's my reducer.js file:
import React from 'react';
import * as actionTypes from '../action/NoNameAction';
const initialState = {
isModalOpen: false
};
const global = (state = initialState, action) => {
switch(action.type) {
case actionTypes.OPEN_MODAL:
return {
...state,
isModalOpen: true,
}
case actionTypes.CLOSE_MODAL:
return {
...state,
isModalOpen: false,
}
default:
return state;
}
};
export default global;
Here's my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux';
import modalOpenReducer from './store/reducer/reducer';
const rootReducer = combineReducers({
isOpen: modalOpenReducer
});
const store = createStore(rootReducer);
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
registerServiceWorker();
change the reducer file name to global.js and in the root.js import it as global instead of reducer.And also in the component,change to this.props.isOpen
I'm a bit confused about redux implementation.
Let's say my app has this component structure:
-App
--ProfilationStep
---ProfilationStep1
----React-Select (http://jedwatson.github.io/react-select/)
I need to use redux because the app is going to grow bigger and deeper, so I started by setting up Actions, Reducers and Action types for the React-Select component. I also set the mapStateToProps in the App.js file.
Now I need to know how to pass/access the data stored in redux to other components (React-Select for example) and how to edit it with the actions I declared.
This is my index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ProfilationSelectReducer from './components/reducers/profilationSelect';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
const store = createStore(
ProfilationSelectReducer
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
This is my App.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import { bindActionCreators} from 'redux'
import Profilation from './components/Profilation'
import ProfilationStep from './components/Profilation/ProfilationStep'
import { connect } from 'react-redux';
import * as SelectActionCreators from './components/actions/profilationSelect'
import 'react-select/dist/react-select.css';
class App extends Component {
static propTypes = {
steps: PropTypes.array.isRequired
};
render() {
console.log(this.props)
const { dispatch, steps } = this.props;
const changeValue= bindActionCreators(SelectActionCreators.changeValue, dispatch);
const stepComponents = this.props.steps.map((step, index) => (
<ProfilationStep
key={index}
index={index}
step={step}
/>
));
return (
<div className="repower-app">
{ stepComponents }
</div>
);
}
}
const mapStateToProps = state => ({
steps:state.steps
});
export default connect(mapStateToProps)(App);
This is my ProfilationStep.js file
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import ProfilationStep1 from './ProfilationStep1'
import ProfilationStep2 from './ProfilationStep2'
import ProfilationStep3 from './ProfilationStep3'
import ProfilationStep4 from './ProfilationStep4'
import ProfilationStep5 from './ProfilationStep5'
const ProfilationStep = props =>
<div className='ProfilationStep'>
{props.index===0 &&
<ProfilationStep1
step={props.step}
/>
}
{props.stepIndex===2 &&
<ProfilationStep2
handleSelect={props.handleSelect}
handleInput={props.handleInput}
expend={props.expend}
period={props.period}
light={props.light}
gas={props.gas}
/>
}
{props.stepIndex===3 &&
<ProfilationStep3
handleSelect={props.handleSelect}
environment={props.environment}
/>
}
{props.stepIndex===4 &&
<ProfilationStep4
flexibility={props.flexibility}
handleSelect={props.handleSelect}
/>
}
{props.stepIndex===5 &&
<ProfilationStep5
customize={props.customize}
handleSelect={props.handleSelect}
/>
}
</div>
export default ProfilationStep
This is my ProfilationStep1.js file
import React, { Component } from 'react';
import Select from 'react-select';
import PropTypes from 'prop-types'
var jobOptions = [
{ value: 'edilizia', label: 'Edilizia' },
{ value: 'editoria', label: 'Editoria' },
{ value: 'educazione', label: 'Educazione' }
];
const ProfilationStep1 = props =>
<div className='ProfilationStep'>
La mia attività si occupa di <Select
name="job"
value={props.step.job}
onChange={e => props.changeValue(e.target.value)}
options={jobOptions}
/>
</div>
ProfilationStep1.propTypes = {
//isComplete: PropTypes.bool.isRequired,
//isActive: PropTypes.bool.isRequired
job: PropTypes.string.isRequired,
service: PropTypes.string.isRequired,
handleSelect: PropTypes.func.isRequired
}
export default ProfilationStep1
This is my reducer
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
const initialState = {
steps: [{
job: "",
service: ""
}],
}
export default function ProfilationSelectReducer (state=initialState, action){
switch(action.type){
case ProfilationSelectActionTypes.CHANGE_VALUE:
return {
...state,
steps:[{
job: action.value
}]
};
default:
return state;
}
}
This is my actiontypes file
export const CHANGE_VALUE ='profilationSelect/CHANGE_VALUE';
and, finally, this is my actions file
import * as ProfilationSelectActionTypes from '../actiontypes/profilationSelect';
export const changeValue = value =>{
return{
type: ProfilationSelectActionTypes.CHANGE_VALUE,
value
}
}
Thank you for any help
You are definitely on the right way.
The solution is simple: You bind your state to the react props. With the props, you can do whatever you like (e.g. pass them to react-select). If you want to modify it, you have to map "mapDispatchToProps", where you map functions, which execute your actions to the props. This works the same as "mapStateTopProps":
End of App.js (import your actions file on top, named "profilationSelectActions" here):
const mapStateToProps = state => ({
steps:state.steps
});
const mapDispatchToProps = dispatch => ({
updateJobValue: (value) => dispatch(profilationSelectActions.changeValue(value))
}
// Also add here mapDispatchToProps
export default connect(mapStateToProps, mapDispatchToProps)(App);
Now the function "updateJobValue" is available in the props of your app.js. You can now easily pass it down to your components and to the onChange event of react-select:
In your ProfilationStep1.js change this line:
onChange={e => props.changeValue(e.target.value)}
To this (after you passed the function updateJobValue down)
onChange{e => props.updateJobType(e.target.value)}
After that, updateJobType should go all the way up to App.js and then dispatch the action. After that, the application will re-render with the new steps.
I'm writing a React-Native application in which I have a screen I need to test:
MyScreen.js
import React, { Component } from "react";
import CustomTable from "./CustomTable";
export default MyScreen extends Component {
render() {
return <CustomTable />;
}
}
CustomTable.ios.js
import React, { Component } from "react";
import { View } from "react-native";
import TableView from "react-native-tableview";
export default MyScreen extends Component {
render() {
return (
<View>
...some stuff
<TableView />
</View>
);
}
}
react-native-tableview calls some iOS specific code so I have mocked it out by simply returning the android version (CustomTable.android.js) in the __mocks__ folder
__mocks__/CustomTable.ios.js
import CustomAndroidTable from "../CustomTable.android";
export const CustomTable = CustomAndroidTable;
What I want to do is test MyScreen.js with Jest, but I want it to use the __mock__/CustomTable.ios. How do I go about getting it to do that? Is that even possible with Jest? My current test file looks like:
tests/MyScreen.test.js
import React from "react";
import renderer from "react-test-renderer";
import MyScreen from "../src/MyScreen";
describe("test", () => {
it("works", () => {
jest.mock("../src/CustomTable.ios");
const tree = renderer.create(
<MyScreen />,
).toJSON();
expect(tree).toMatchSnapshot();
});
But it still calls the original version of CustomTable.ios. What am i doing wrong?
You should call jest.mock outside of your suite test. It should be immediately after your imports.
import React from "react";
import renderer from "react-test-renderer";
import MyScreen from "../src/MyScreen";
jest.mock("../src/CustomTable.ios");
describe("test", () => {
it("works", () => {
const tree = renderer.create(
<MyScreen />,
).toJSON();
expect(tree).toMatchSnapshot();
});