I'm new to Electron and I am clueless as to how to access the Electron's process object from my app.js component.
This is my function createWindow
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: { nodeIntegration: true },
});
mainWindow.loadURL("http://localhost:3000/");
mainWindow.on("closed", function () {
mainWindow = null;
});
}
And this is my app.js component
class App extends React.Component {
componentDidMount() {
console.log("process", process);
}
render() {
return <h1>Hello</h1>;
}
}
At the moment, I am able to launch the app and the render app.js, but I can't access the process object from there.
After trying multiple things, this simple solution worked:
componentDidMount() {
console.log("process", window.process);
}
Related
I've got a React application created with create-react-app and I'm trying to integrate Phaser 3 as well. I followed this guide to get started. I've got the canvas rendering the text but loading images in the preload does not seem to be working. I get the default failed to load texture image displayed.
import ExampleScene from "./scenes/ExampleScene";
import * as React from "react";
export default class Game extends React.Component {
componentDidMount() {
const config = {
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene]
};
new Phaser.Game(config);
}
shouldComponentUpdate() {
return false;
}
render() {
return <div id="phaser-game" />;
}
}
ExampleScene:
import Phaser from "phaser";
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", "assets/logo.png");
}
create() {
const text = this.add.text(250, 250, "Phaser", {
backgroundColor: "white",
color: "blue",
fontSize: 48
});
text.setInteractive({ useHandCursor: true });
this.add.image(400, 300, "logo");
text.on("pointerup", () => {
console.log("Hello!");
//store.dispatch({ type: ACTION_TYPE });
});
}
}
The idea is to create a visualization with flowers growing based on a simple gene engine. So Phaser would get instructions from the Store about the current state.
I'm guess this has something to do with the way Phaser loads and there's a conflict with how React updates. I'm preventing the component from updating as I only need the game to receive instructions by listening to the store
I've already looked at this SO answer and the accompanying wrapper, but it is outdated.
How can I get Phaser to load images when in a Create-React-App?
CodeSandbox: https://codesandbox.io/s/github/nodes777/react-punnett/tree/phaser-game
Repo: https://github.com/nodes777/react-punnett/tree/phaser-game
Other option is using WebComponents to be able to integrate Phaser with any other framework (React, Angular, VueJS, etc), check this npm package: https://www.npmjs.com/package/#ion-phaser/core
Also, you can use the React wrapper of that library to use Phaser with React components easily, so you don't need to manipulate WebComponents directly, example:
import React from 'react'
import Phaser from 'phaser'
import { IonPhaser } from '#ion-phaser/react'
const game = {
width: "100%",
height: "100%",
type: Phaser.AUTO,
scene: {
init: function() {
this.cameras.main.setBackgroundColor('#24252A')
},
create: function() {
this.helloWorld = this.add.text(
this.cameras.main.centerX,
this.cameras.main.centerY,
"Hello World", {
font: "40px Arial",
fill: "#ffffff"
}
);
this.helloWorld.setOrigin(0.5);
},
update: function() {
this.helloWorld.angle += 1;
}
}
}
const App = () => {
return (
<IonPhaser game={game} />
)
}
export default App;
Fore more details check the repo: https://github.com/proyecto26/ion-phaser/tree/master/react
A year ago I was here looking for the answer myself. Here's pattern which should work.
import Phaser from "phaser"
import React, { useEffect, useState } from "react"
/** #tutorial I made this! This answers how you get your image. */
import logoImage from "./path-to-logo.png"
/** #tutorial I made this! Use a functional React component and `useEffect` hook.*/
export const Phaser3GameComponent = ({ someState }) => {
// Optional: useful to delay appearance and avoid canvas flicker.
const [isReady, setReady] = useState(false)
// Just an example... do what you do here.
const dataService = (changedState) => {
// I'm not sure how to use stores, but you'll know better what to do here.
store.dispatch(
{
...someState,
...changedState,
},
{ type: ACTION_TYPE }
)
}
// This is where the fun starts.
useEffect(() => {
const config = {
callbacks: {
preBoot: game => {
// A good way to get data state into the game.
game.registry.merge(someState)
// This is a good way to catch when that data changes.
game.registry.events.on("changedata", (par, key, val, prevVal) => {
// Simply call whatever functions you want outside.
dataService({ [key]: val })
})
},
},
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene],
}
let game = new Phaser.Game(config)
// Triggered when game is fully READY.
game.events.on("READY", setReady)
// If you don't do this, you get duplicates of the canvas piling up.
return () => {
setReady(false)
game.destroy(true)
}
}, []) // Keep the empty array otherwise the game will restart on every render.
return (
<div id="phaser-example" className={isReady ? "visible" : "invisible"} />
)
}
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", logoImage)
}
create() {
// You made this!
const text = this.add.text(250, 250, "Phaser")
text.setInteractive({ useHandCursor: true })
this.add.image(400, 300, "logo")
/** #tutorial I made this! */
// Get all that lovely dataState into your scene,
let { clickCount } = this.registry.getAll()
text.on("pointerup", () => {
// This will trigger the "changedata" event handled by the component.
this.registry.merge({ clickCount: clickCount++ })
})
// This will trigger the scene as now being ready.
this.game.events.emit("READY", true)
}
}
I started from scratch and created my own boilerplate from the phaser 3 template. I wrote about the specific steps to add React to the Phaser 3 template here.
It seems like you could eject from Create-React-App and add in Phaser 3 from there, but the warnings not to eject turned me away from that solution.
In my case I use the following component and it works fine:
import Phaser from 'phaser';
import * as React from 'react';
import { HTML_DIV_ID, gameConfig } from './gameConfig';
export const GameWrapper = () => {
const [game, setGame] = React.useState<Phaser.Game>();
React.useEffect(() => {
const _game = new Phaser.Game(gameConfig());
setGame(_game);
return (): void => {
_game.destroy(true);
setGame(undefined);
};
}, []);
return (
<>
<div id={HTML_DIV_ID} />
</>
);
};
With create-react-app and React.StrictMode:
Also I deleted React.StrictMode (default option with create-react-app) because it mounts
and unmounts all components so I had unexpected behavior with phaser
sometimes
You can use react hook for the code above as:
// usePhaser.js
export function userPhaser(config) {
const [game, setGame] = React.useState();
React.useEffect(() => {
const _game = new Phaser.Game(config);
setGame(_game);
return (): void => {
_game.destroy(true);
setGame(undefined);
};
}, []);
return game;
}
You need to put images inside the folder public!
For me, I see the best practice to use both of them properly is to create phaser project separately and host it separately using firebase or whatever hosting service you prefer, and then take the link and put it in an iframe tag inside react.
in this way you can manage them efficiently and you can manipulate react website in more comfortable way especially the mobile width compatibility.
I have a terminal component that render a terminale emulator.
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import { XTerm } from '../../node_modules/react-xterm';
import os from 'os';
import { connect } from 'react-redux';
import '../../node_modules/xterm/dist/xterm.css';
const pty = require('node-pty');
const mapStateToProps = (state) => {
return state;
};
class Terminal extends Component {
constructor(props) {
super(props);
this.xtermLoaded = false;
this.ptyProcess = null;
this.term = null;
this.shell = process.env[os.platform() === 'win32' ? 'COMSPEC' : 'SHELL'];
this.ptyProcess = pty.spawn(this.shell, [], {
name: 'xterm-color',
cols: 50,
rows: 30,
cwd: process.cwd(),
env: process.env
});
}
bindXterm(xterm) {
if (!xterm || this.xtermLoaded) return;
let term = xterm.getTerminal();
if (!term.on) return;
this.term = term;
this.xtermLoaded = true;
this.term.on('data', data => {
this.ptyProcess.write(data);
});
this.ptyProcess.on('data', data => {
this.term.write(data);
});
}
render() {
return (
<XTerm style={{
addons: ['fit', 'fullscreen'],
overflow: 'hidden',
position: 'relative',
width: '100%',
height: '100%'
}} ref={xterm => this.bindXterm(xterm)}/>
);
}
}
export default connect(mapStateToProps)(withStyles(styles)(Terminal));
With this.ptyProcess.write(data), i can write new things into the terminal.
But how i can access to this.ptyProcess.write(data) from another component ?
Can someone help me please ? :)
Thanks.
Presumably this component is created either by another component, or by a call to ReactDOM.Render(). You should make ptyProcess a member of the nearest common ancestor of all the components that need to access it, and then pass it down to them as part of the props object.
As a general rule in react, if a property needs to be shared by multiple child components, then you should "hoist" that property up into the parent component and pass it down to the children through props.
You are already using redux. Just include a dataForTerminal reducer that when changes, new data are written into the terminal.
So create an action creator for it and then you can call the action creator from any component
I'm using create-react-app to design a PWA. The default Splash screen provided by the App is an icon (in middle of the screen) and a name of the app below that icon. Icon & name must be provided in the manifest file.
Question: Is there any way to customize the Splash Screen instead of using the default one?
Following is the possible solution but searching for a better way to do that.
Possible Solution:
Add a component for Splash Screen.
On the main component, render SplashScreen component untill the API response is returned from the server. I am using renderSplashscreen state for rendering the SplashScreen component.
// Component for Splash Screen
class SplashScreen extends React.Component {
render() {
const style = {top: 0,
bottom: 0,
right: 0,
left: 0,
position: 'fixed'};
return (
<img src={'IMAGE-URL'} style={style}/>
);
}
}
class MainComponent extends React.Component {
constructor(props) {
this.state = {
renderSplashscreen: true
};
}
apiCallback(data) {
// After getting the API response from server
this.setState({renderSplashscreen: false});
}
render() {
let view;
if(this.state.renderSplashscreen)
return <SplashScreen/>;
else
return <OtherComponent/>
}
}
Here's my own possible solution added in the question, as for now, this is the only solution that works well.
Add a component for Splash Screen.
On the main component, render SplashScreen component untill the API response is returned from the server. I am using renderSplashscreen state for rendering the SplashScreen component.
// Component for Splash Screen
class SplashScreen extends React.Component {
render() {
const style = {top: 0,
bottom: 0,
right: 0,
left: 0,
position: 'fixed'};
return (
<img src={'IMAGE-URL'} style={style}/>
);
}
}
class MainComponent extends React.Component {
constructor(props) {
this.state = {
renderSplashscreen: true
};
}
apiCallback(data) {
// After getting the API response from server
this.setState({renderSplashscreen: false});
}
render() {
let view;
if(this.state.renderSplashscreen)
return <SplashScreen/>;
else
return <OtherComponent/>
}
}
I am trying to understand how I could use React for rendering all the UI elements and Phaser for rendering a game (using Canvas or WebGL) within the React application.
One way would be to use React's componentDidMount, so after I have my HTML ready I can use a div id to render the Phaser content. In this case who does the rendering? React of Phaser?
If the mentioned way is not the right one, could you suggest another?
There is a module for this on Github called react-phaser. Here is a CodePen that does not use any separate module.
var PhaserContainer = React.createClass({
game: null,
...
componentDidMount: function(){
this.game = new Phaser.Game(800, 400, Phaser.AUTO, "phaser-container",
{
create: this.create,
update: this.update
});
},
...
render: function(){
return (
<div className="phaserContainer" id="phaser-container">
</div>
);
}
...
}
This is not my CodePen. Credit goes to Matthias.R
Check this new WebComponent to integrate Phaser with any other framework 👍 https://github.com/proyecto26/ion-phaser
Example:
import React, { Component } from 'react'
import Phaser from 'phaser'
import { IonPhaser } from '#ion-phaser/react'
class App extends Component {
state = {
initialize: false,
game: {
width: "100%",
height: "100%",
type: Phaser.AUTO,
scene: {}
}
}
render() {
const { initialize, game } = this.state
return (
<IonPhaser game={game} initialize={initialize} />
)
}
}
I'm getting this error even though i'm passing in the navigator porp properly.
MySetup is in this way : Main navigator Page -> FirstView (onBtnPress) -> Details
I'm getting the error when i'm calling this.navigator.push in the firstView page.
Main File:
import React, { Component, PropTypes } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Navigator
} from 'react-native';
class app extends Component{
constructor(props) {
super(props);
}
navigatorRenderScene(route, navigator) {
return <route.component navigator={navigator}/>
}
configureScene() {
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}
render() {
return (
<Navigator
style={styles.container}
initialRoute= {{component: MainMapView}}
renderScene={this.navigatorRenderScene}/>
);
}
}
const styles = StyleSheet.create({
container: { flex: 1, flexDirection: 'column', padding: 20 }
});
AppRegistry.registerComponent('app', () => app);
First Component:
<ActionButton buttonColor="rgba(30,144,255,1)" style={styles.fabIcon}
onPress={this.fabPress}>
</ActionButton>
fabPress() {
this.props.navigator.push({
component : DetaislView
});
}
The error occurs on fabPress.
Any ideas on what i'm doing wrong?
try this in your FirstComponent.js:
class FirstComponent extends Component {
constructor(props) {
super(props);
this.fabPress = this.fabPress.bind(this);
}
// ... rest of the code remains the same
Why we had to do this?
Back in time when we were using React.createClass (ES5), class methods were automatically bound to the class. But when we started to extend (ES6 classes), we need to bind the methods explicitly to the class env.
fabPress being passed as an event's callback function, it is executed in another env outside the class; hence the this will be coming from the scope of execution env. But we need this of our class to access this.props.navigator :)
Just in case if anyone is interested in why this doesn't work even if you are having the function inside the class.
The function isn't binded to the class if declared as shown in the following.
theFunctionName() {
// your code
}
The function is binded to the class if it is declared with the following syntax.
theFunctionName = () => {
// your code
}
thus you can omitt the bind(this) code.
reference taken from here
Please make sure you have the necessary presets. Since the arrow function is highly experimental feature (as of this period in time)
For my case I passed in the navigator:
onPress={this.fabPress(navigator)}
fabPress(navigator) {
navigator.push({component: DetaislView});
}