I was integrating gojs with react and was successfully able to integrated the nodes array and links array and was able to see the nodes in my page.
But the toughest thing , integrated ReactOverview (minimap) but i can see only small rectangle box on the page with no diagram in it.
Will share my code here
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { ReactDiagram, ReactOverview } from 'gojs-react';
import * as go from 'gojs';
class DiagramContainer extends React.Component {
diagramRef;
static propTypes = {
diagramData: PropTypes.object.isRequired,
};
constructor(props) {
super(props);
this.diagramRef = React.createRef();
this.state = {};
}
initDiagram = () => {
const $ = go.GraphObject.make;
const diagram = $(go.Diagram, {
'undoManager.isEnabled': true,
'animationManager.isEnabled': false,
// 'undoManager.maxHistoryLength': 0,
model: $(go.GraphLinksModel, {
linkKeyProperty: 'key',
linkFromPortIdProperty: 'fromPort',
linkToPortIdProperty: 'toPort',
}),
});
const defaulttemplate = $(
go.Node,
'Vertical',
$(
go.Panel,
'Auto',
$(
go.Shape,
'hexagon',
{
width: 160,
height: 160,
},
),
$(
go.TextBlock,
}
)
);
var templateMap = new go.Map();
templateMap.add('normal', defaulttemplate);
//dummy codes
},
})
);
return diagram;
};
initDiagramOverview = () => {
const $ = go.GraphObject.make;
const overview = $(go.Overview, { contentAlignment: go.Spot.Center });
return overview;
};
render() {
const { diagramData } = this.props;
return (
<>
<div style={{ height: '100%' }}>
<ReactDiagram
ref={this.diagramRef}
divClassName='diagram-main'
id='diagram'
initDiagram={this.initDiagram}
flowDiagramData={diagramData}
nodeDataArray={diagramData.dataArray}
linkDataArray={diagramData.linksArray}
skipsDiagramUpdate={diagramData.skipsDiagramUpdate}
modelData={}
/>
</div>
<ReactOverview
initOverview={this.initDiagramOverview}
divClassName='diagram-observed'
observedDiagram={this.diagramRef.current?.getDiagram() || null}
/>
</>
);
}
}
export default DiagramContainer
```
But am not seeing mini map , i can just see a rectangle box instead of minimap. Still i cross checked with various things and am not sure what went wrong
Can you guys help me to resolve this issue
The problem is that your component only renders once for the given props (any interactive diagram changes are handled internally by GoJS and React is oblivious to that). When it renders the first and only time, this.diagramRef.current is still null. You can see this if you log it in the render method.
You need to use state to keep the "observed diagram" for the overview. Then when the overview component initializes, the diagram should be all set up and you can set the new state to cause re-render:
Add the state with the value of the diagram you want to observe in the overview:
constructor(props) {
super(props);
this.state = {
observedDiagram: null
};
this.diagramRef = React.createRef();
}
Use this state in the ReactOverview component:
<ReactOverview
initOverview={this.initDiagramOverview}
divClassName="diagram-overview-component"
observedDiagram={this.state.observedDiagram}
/>
Set the state when initializing the overview component:
initDiagramOverview = () => {
this.setState({
observedDiagram: this.diagramRef.current?.getDiagram() || null
});
const $ = go.GraphObject.make;
const overview = $(go.Overview, { contentAlignment: go.Spot.Center });
return overview;
};
You can see how it works in this sandbox
Related
I have a problem to reinitialize the ion-phaser function component in a parent component. It works fine by reinitilization just as a class component. Bellow are the two examples to displays which works and which not.
Here is my parent render function:
render() {
return(
<>
{this.state.visible && <IonComponent />}
</>
)
}
Here is the Ion-Phaser function component (this doesn't work):
let game = { ..here comes the Phaser game logic }
const IonComponent = () => {
const [initialize, setInitialize] = useState(false);
useEffect(() => {
if (game?.instance === undefined) {
setInitialize(true);
}
}, [initialize]);
return (
<>
{ initialize && <IonPhaser game={game} initialize={initialize} />}
</>
)
}
export default IonComponent;
Here is the Ion-Phaser class component (this works):
class IonComponent extends React.Component {
state = {
initialize: true,
game: { ..here comes the Phaser game logic }
}
render() {
const { initialize, game } = this.state
return (
<IonPhaser game={game} initialize={initialize} />
)
}
}
export default IonComponent;
When I switch in the parent component the state.visible at the first render to true, it initiate the child IonPhaser component without any problems. But after the state.visible switch once to false and then again back to true, the function component will not reinitialize and it removes the canvas from the dom. The class component however works fine.
Is this a persistent bug in Ion-Phaser by function component or am I doing something wrong?
Make sure you're keeping track of the state of your game using React's useState() hook or something similar.
For what it's worth, I also ran into some issues while trying to get the IonPhaser package working. To get around these issues, I've published an alternative way to integrate Phaser and React here that (I think) is more straightforward.
It works mostly the same way, but it doesn't come with as much overhead as the IonPhaser package.
npm i phaser-react-tools
And then you can import the GameComponent into your App.js file like so:
import { GameComponent } from 'phaser-react-tools'
export default function App() {
return (
<GameComponent
config={{
backgroundColor: '000000',
height: 300,
width: 400,
scene: {
preload: function () {
console.log('preload')
},
create: function () {
console.log('create')
}
}
}}
>
{/* YOUR GAME UI GOES HERE */}
</GameComponent>
)
}
It also comes with hooks that let you emit and subscribe to game events directly from your React components. Hope this helps, and please get in touch if you have feedback.
i have a select menu with defaultValue is null
when i pass props to it , it dosent rerender with the new props as defaultValues
ps : the select is multi
i tried to use component will recieve props and everything that i find but still dosent work
this is my select component :
import React, { useState, useEffect } from "react";
import Select from "react-select";
class SelectMenu extends React.Component {
state = {
defaultValues: [],
};
componentWillReceiveProps(newProps) {
this.setState({ defaultValues: newProps.defaultValue });
}
render() {
return (
<Select
options={this.props.options}
closeMenuOnSelect={this.props.closeMenuOnSelect}
components={this.props.components}
isMulti={this.props.isMulti}
onChange={(e) => this.props.onChange(e, this.props.nameOnState)}
placeholder={this.props.default}
defaultValue={this.state.defaultValues}
/>
);
}
}
export default SelectMenu;
componentWillReceiveProps won't be called during mounting.
React doesn’t call UNSAFE_componentWillReceiveProps() with initial props during mounting. It only calls this method if some of component’s props may update. (https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops)
Also, componentWillReceiveProps is deprecated and will be removed in React 17. Take a look at getDerivedStateFromProps instead, and especially the notes on when you do not need it.
I beleive that in your case using the constructor will be perfectly fine, something like:
class Components extends React.Component {
constructor(props) {
super(props)
this.state = { some_property: props.defaultValue }
}
}
i find a solution for this problem
by using components will recieve props
and setting my state with the comming props
and in the render you need to do condition to render the select menu only if the state.length !== 0
i posted this answer just in case someone face the same problem i know its not the most optimal solution but it works for me
sorry for the previous solution but its not optimal i find a way to make it work
so instead of defaultvalues
you have to make its as value props
and if you want to catch the deleted and added values to your default
this function will help you alot
onChange = (e) => {
if (e === null) {
e = [];
}
this.setState({
equipments: e,
});
let added = e.filter((elm) => !this.state.equipments.includes(elm));
if (added[0]) {
let data = this.state.deletedEquipments.filter(
(elm) => elm !== added[0].label
);
this.setState({
deletedEquipments: data,
});
}
let Equipments = e.map((elm) => elm.label);
let newEquipments = Equipments.filter(
(elm) => !this.state.fixed.includes(elm)
);
this.setState({
newEquipments: newEquipments,
});
let difference = this.state.equipments.filter((elm) => !e.includes(elm));
if (difference.length !== 0) {
if (
!this.state.deletedEquipments.includes(difference[0].label) &&
this.state.fixed.includes(difference[0].label)
) {
this.setState({
deletedEquipments: [
...this.state.deletedEquipments,
difference[0].label,
],
});
}
}
};
constructor(props) {
super(props);
this.state = {
equipments: [],
newEquipments: [],
deletedEquipments: [],
};
}
I am using react-admin framework (3.2) and I am struggling with following error:
ReferenceError: Cannot access 'GameScheduleField' before initialization
This is how I import the GameScheduleField component to my resource:
import { GameScheduleField, GameScheduleInput } from '../components/GameScheduleComponents';
I also import atleast eight other components without any issue. The GameScheduleField is a class and it looks like this:
export class GameScheduleField extends React.Component
{
constructor(props, context)
{
super(props, context);
};
static defaultProps =
{
addLabel: false,
}
rowStyle = (record, index, defaultStyle = {}) =>
{
const style = color => ({
...defaultStyle,
borderLeftWidth: 5,
borderLeftStyle: "solid",
borderLeftColor: color,
});
switch (record.type)
{
case "q": return style("yellow");
case "v": return style("cyan");
case "adv": return style("magenta");
case "fin": return style("green");
default: return style("gray");
}
}
render()
{
const { source, record, ...rest } = this.props;
const seq = get(record, source, []).map((v, i) => ({ order: i + 1, ...v }));
return <ArrayField record={{ data: seq }} source="data" {...rest}>
<Datagrid rowClick="expand" rowStyle={this.rowStyle} expand={<GameStepField />} setSort={() => {}}>
<TextField source="order" label="hf.order" />
<SelectField source="type" choices={GameStepEnum} />
</Datagrid>
</ArrayField>
}
}
Any suggestion why am I getting this error linked to this specific component?
Thank you in advance.
This happens when u have circular dependency. for example. follow below given comment.
You have a circular dependency issue:
http/private : import store from "app" components/headerNav: import
apiPrivate from "http/private"; and then app imports your component
tree So, because of that, http/private is going to get loaded first
and try to grab the store from app, except app hasn't actually been
loaded yet because it's waiting on the component tree to be imported.
Source:
https://github.com/reduxjs/redux-toolkit/issues/167
My desire is to implement the 'Dat.gui' library for my 'Three.js' project using React Hooks.
When implementing with es6
I get the desired look i want, but i struggle to send and update values due to not having any statehandling.
import React from 'react'
import * as dat from 'dat.gui';
var FizzyText = function() {
this.message = 'dat.gui';
this.speed = 0.8;
this.displayOutline = false;
};
var text = new FizzyText();
var gui = new dat.GUI();
gui.add(text, 'message');
gui.add(text, 'speed', -5, 5);
gui.add(text, 'displayOutline');
export default function GUIHandler() {
return (
<div>
</div>
)
}
The desired look using the code above
The React implementation(using react class component)
import React from 'react';
import DatGui, { DatBoolean, DatColor, DatNumber, DatString } from 'react-dat-gui';
export default class GUIHandler extends React.Component {
state = {
data: {
package: 'react-dat-gui',
power: 9000,
isAwesome: true,
feelsLike: '#2FA1D6',
}
}
// Update current state with changes from controls
handleUpdate = newData =>
this.setState(prevState => ({
data: { ...prevState.data, ...newData }
}));
render() {
const { data } = this.state;
return (
<DatGui data={data} onUpdate={this.handleUpdate}>
<DatString path='package' label='Package' />
<DatNumber path='power' label='Power' min={9000} max={9999} step={1} />
<DatBoolean path='isAwesome' label='Awesome?' />
<DatColor path='feelsLike' label='Feels Like' />
</DatGui>
)
}
}
The React code look unfortunatley it gets stuck outside the canvas and just looks bad
Any recommendations on how i can get this to work (preferably with React hooks) would be much appreciated.
In the following code, when setState is called from campaignsUpdated, render gets logged to the console, but not renderRow:
var React = require('react-native'),
Bus = require('../Bus'),
styles = require('../Styles'),
CampaignsStore = require('../stores/Campaigns'),
CampaignItem = require('./CampaignItem'),
{
Component,
Text,
TextInput,
ListView,
View,
NavigatorIOS,
ActivityIndicatorIOS
} = React
class CampaignList extends Component {
constructor(props) {
super(props)
this.state = {
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
}
}
componentDidMount() {
this.addListeners()
Bus.emit('campaigns:search', '')
}
componentWillUnmount() {
this.removeListeners()
}
render() {
console.log('render')
return (
<View style={styles.container}>
<TextInput
style={styles.searchInput}
placeholder='Campaign Name'
value={this.state.campaignName}
onChange={this.campaignSearchChanged.bind(this)}/>
<ListView
dataSource = {this.state.dataSource}
renderRow = {this.renderRow.bind(this)}/>
</View>
)
}
renderRow(campaign) {
console.log('renderRow')
return <CampaignItem campaign={campaign}/>
}
addListeners() {
Bus.on({
'campaigns:updated': this.campaignsUpdated.bind(this)
})
}
removeListeners() {
Bus.off({
'campaigns:updated': this.campaignsUpdated.bind(this)
})
}
campaignsUpdated(event) {
var campaigns = event.data
this.setState({
dataSource: this.state.dataSource.cloneWithRows(campaigns)
})
}
campaignSearchChanged(event) {
var campaignName = event.nativeEvent.text
Bus.emit('campaigns:search', campaignName)
}
}
module.exports = CampaignList
What am I doing wrong here?
You are passing ListView a function renderRow that returns a component. You would have to call that function within ListView once it is passed, presumably during a map over campaigns.
By the looks of it the most likely case is that you have a classic React mutability issue here.
I.e. I suspect your 'campaignsUpdated' method is called with either the same Array instance it received last time, or the elements within the list are the same instances.
Try using:
campaignsUpdated(event) {
var campaigns = event.data.slice(); // <-- clone the array
this.setState({
dataSource: this.state.dataSource.cloneWithRows(campaigns)
})
}
If that doesn't work, then you either make the part that manages your list of compaigns create new copies when changes are made (e.g. const clone = {...campaign, title:"A new Title"}) or update your rowHasChanged method to see if the title (or whatever data you need) has actually changed.
Here are two really good videos about immutability in JavaScript here:
https://egghead.io/lessons/javascript-redux-avoiding-array-mutations-with-concat-slice-and-spread
https://egghead.io/lessons/javascript-redux-avoiding-object-mutations-with-object-assign-and-spread