What is a point in react. We have props who's readOnly and i cant edit it and we have state also can't edit from out of class space ?!
I follow tutorials ...
if i setup {this.state.myStyle} , myStale become's readonly ?!
Here is whole class :
import * as React from "react";
import { CSSProperties } from "react";
import * as ReactDOM from "react-dom";
import { Label } from "../../components/label/label";
import IApp from "../../interfaces/global-interfaces";
import Services from "../../services/services";
import { HeaderI, HeaderStateI } from "./header-interface";
// import { myStyle } from "./style";
enum myEventList {
iNeedSomeUpdate = "i-need-some-update",
}
export class Header extends React.Component< HeaderI, HeaderStateI , any > {
public myEvent = Services.CreateEvent(myEventList.iNeedSomeUpdate, {self: this} );
public myRef: React.RefObject<HTMLDivElement>;
public myDOM: Element | Text;
private myStyle: IApp.MyMinimumCssInterface = {
display: "block",
background: "#559d96",
height: "100px",
textAlign: "center",
};
constructor(args: any) {
super(args);
this.state = { enabledComponent : true,
visibility: true,
debugView: false,
background: args.background,
elements: [],
// tslint:disable-next-line:object-literal-shorthand
myStyle: this.myStyle,
};
// e.detail.data.self..background = this.state.background;
this.myRef = React.createRef();
this.add = this.add.bind(this);
}
// Override func
public componentDidMount() {
this.myDOM = this.myRef.current;
this.myDOM.addEventListener(myEventList.iNeedSomeUpdate, this.updateOnMyEvent);
}
public updateOnMyEvent(e: CustomEvent) {
e.detail.data.self.printMe();
console.log("My custom event is done!");
e.detail.data.self.adapt();
}
public printMe() {
console.log("Layout Header is active and update is on");
}
public render() {
if ( this.state.debugView === false ) {
return (
<div ref={this.myRef} style={this.state.myStyle} onClick={this.TestEvent.bind(this)} >
<Label name="headerName" text="i am header paragraph!" />
{this.state.elements.map((i: any) => {
return <span key={i} >{i}</span>;
})}
</div>
);
} else {
this.printMe();
return (
<div style={this.state.myStyle} ref={this.myRef} >
<Label name="headerName" text="i am header paragraph!"/>
{this.state.elements.map((i: any) => {
return <li key={i} >{i}</li>;
})}
</div>
);
}
}
public componentDidUpdate(prevProps: any) {
// Typical usage (don't forget to compare props):
console.warn("prevProps name is: " + prevProps.name);
if (this.props.background !== prevProps.background) {
this.printMe();
} else {
console.log("Background is same no update.");
}
}
public add = (id: number, content: any, event: any ) => {
let localArr: any[] = [];
localArr = this.state.elements;
localArr.push(React.createElement("div", { key: id , onClick : null }, content));
this.setState(
{
elements: localArr,
visibility : false,
},
);
// tslint:disable-next-line:no-unused-expression
console.log(" add from class in state elements, visible is " , this.state.visibility );
}
public TestEvent(event: MouseEvent) {
this.add( 1 , "fffff", null);
this.add( 2 , "zzzzzz", null);
this.myDOM.dispatchEvent(this.myEvent);
}
public adapt() {
this.myStyle.background = "lime";
this.setState({
myStyle: this.myStyle,
});
}
}
Because myStyle is 'frozen', you need to clone the object, make changes and then write it back using setState.
In ES6 you can use a pattern like this:
public adapt() {
const {myStyle} = this.state
let newMyStyle = {...myStyle}
newMyStyle.background = "lime";
this.setState({
myStyle: newMyStyle,
});
}
There are several ways how to manage this i.e.
const myStyle = Object.assign({}, this.state.myStyle, { background: "lime" })
this.setState({ myStyle })
Related
I have two class components: Title and PlayButton. By default, the Title is programmed to change images when it is being hovered over but I would like it so that when the Playbutton is hovered over, the Title also changes its image (changes the state of the image). How would I go about this? I know I should use a parent component that handles the state of both its "children" (the Title and the PlayButton), but since I'm new to react, I'm not sure how.
Any assistance would be appreciated, thank you!
Code for Title:
import React from 'react'
import './Title.css'
import playHoverProvider from './playHoverProvider'
class Title extends React.Component {
constructor(props) {
super(props);
this.state = {
imgSrc: require('./oglogo'),
control: require('./oglogo')
};
this.handleMouseOver = this.handleMouseOver.bind(this);
this.handleMouseOut = this.handleMouseOut.bind(this);
}
handleMouseOver() {
this.setState({
imgSrc: require('./difflogo')
});
}
handleMouseOut() {
this.setState({
imgSrc: require('./oglogo')
});
}
render() {
return (
<div className='logo'>
<view>
<img onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} src={this.state.imgSrc}
style={{width: 800,
flex: 1,
height: null,
}}
alt = 'Logo' />
</view>
</div>
);
}
}
Title.propTypes = {
}
Title.defaultProps = {
}
export default Title;
Code for PlayButton:
import { hover } from '#testing-library/user-event/dist/hover';
import React from 'react'
import './PlayButton.css';
class PlayButton extends React.Component {
constructor(props) {
super(props);
this.state = {
imgSrc: require('./playbutton.png'),
disabled: false
};
this.handleMouseOver = this.handleMouseOver.bind(this);
this.handleMouseOut = this.handleMouseOut.bind(this);
}
// On-click
handleClick = (event) => {
if (this.state.disabled) {
return;
}
this.setState({
disabled: true
});
}
handleMouseOver () {
this.setState({
imgSrc: require('./playbuttonblue.png')
});
}
handleMouseOut () {
this.setState({
imgSrc: require('./playbutton.png')
});
}
render() {
return (
<div className='playbutton'>
<a href='./Rule'>
<button className='buttonprop' onClick={this.handleClick} disabled={this.state.disabled}>
{this.state.disabled ? '' :
<img onMouseOver={this.handleMouseOver}
onMouseOut={this.handleMouseOut}
src={this.state.imgSrc} width = {100} height = {50} alt = 'Play'/>}
</button>
</a>
</div>
);
}
}
PlayButton.propTypes = {
}
PlayButton.defaultProps = {
}
export default PlayButton
I'm trying to figure out why the shouldComponentUpdate method doesn't fire.
Here are what my props looks like:
Object
children: [Object, Object, Object, Object, Object] (5)
data: Array (2)
0 {id: 1, activated: true}
1 {id: 2, activated: true}
key: undefined
rowRender: function()
I have the following snippet.
export function withState(WrappedGrid) {
return class StatefulGrid extends React.Component {
constructor(props) {
super(props);
setInterval(() => console.log(this.props), 5000)
}
shouldComponentUpdate(){
console.log("props updated")
return true
}
componentDidUpdate(prevProps, prevState) {
console.log("update")
}
render() { ... }
}
}
Creating StatefulGrid component :
const StatefulGrid = withState(Grid);
class NFTTable extends React.Component {
constructor({rules}){
super()
this.rules = rules
this.renderers = new Renderers()
this.contextMenu = false
}
render(){
return([
<StatefulGrid
key={"table"}
data={this.rules}
rowRender={this.renderers.rowRender}
>
// GridColumn ...
</StatefulGrid>,
<ContextMenu
key={"context_menu"}
caller={this.renderers.caller}
/>
])
}
}
Updating the data :
export default class ContextMenu extends React.Component{
constructor({caller}){
super()
this.state = {
show: false
}
caller(this)
}
handleContextMenu = (e, dataItem) => {
e.preventDefault()
this.dataItem = dataItem
this.offSet = { left: e.clientX, top: e.clientY }
this.activated = dataItem.dataItem.activated
this.setState({ show: true })
}
componentDidMount() {
document.addEventListener('click', () => {
if(this.state.show)
this.setState({ show: false })
})
}
handleSelect = (e) => {
switch(e.item.data){
case "activation":
this.toggleActivation()
break
default:
console.log("Error, non registered event " + e.data)
}
}
toggleActivation(){
this.dataItem.dataItem.activated = !this.dataItem.dataItem.activated;
}
render() {
return (
<Popup show={this.state.show} offset={this.offSet}>
<Menu vertical={true} style={{ display: 'inline-block' }} onSelect={this.handleSelect}>
<MenuItem data="delete" text="Delete rule"/>
<MenuItem data="activation" text={this.activated ? "Deactivate Rule" : "Activate rule"}/>
</Menu>
</Popup>
);
}
}
Calling handleContextMenu :
export default class Renderers {
rowRender = (trElement, dataItem) => {
let greyed = { backgroundColor: "rgb(235,235,235)" }
let white = { backgroundColor: "rgb(255,255,255)" }
const trProps = {
...trElement.props,
style: dataItem.dataItem.activated ? white : greyed,
onContextMenu : (e) => {
this.contextMenu.handleContextMenu(e, dataItem)
}
};
return React.cloneElement(trElement, { ...trProps }, trElement.props.children);
}
caller = (contextMenu) => {
this.contextMenu = contextMenu
}
}
For debugging purpose, I've added a setInterval method. Through another snippet in my code, I do change props.data[0].activated to false and the changes do reflect in the console log. So why is shouldComponentUpdate not triggered and how to get it to trigger ?
How to make state change from outside of class or from prop.SomeFunction () ?
I use typescript in combination. Yes i already have the class :
CLASS :
import * as React from "react";
import { Label } from "../../components/label/label";
import { TextBox } from "../../components/textBox/textBox";
import IApp from "../../interfaces/global-interfaces";
import { myStyle } from "./style";
interface HeaderI {
background: string;
myFunc(): void;
// elements: any[];
// add(id: number, content: any, event: any): void;
}
interface HeaderStateI extends IApp.ElementI {
background: string;
elements: any[];
}
export class Header extends React.Component< HeaderI, HeaderStateI , any > {
public myRef: React.RefObject<Label>;
constructor(args: any) {
super(args);
this.state = { enabledComponent : true,
visibility: true,
debugView: false,
background: args.background,
elements: [],
};
this.myRef = React.createRef();
this.add = this.add.bind(this);
console.log("state elements:" , this.state.elements);
}
public test() {
alert("Y click on header element");
}
public printMe() {
console.log("Layout Header is active :");
}
// setText = (e: React.ChangeEvent) => {
// this.setState ( { enabledComponent : true , background : (e.target as HTMLInputElement).value } );
// }
public render() {
if ( this.state.debugView === false ) {
return (
<div style={myStyle} onClick={this.addN} >
<Label name="headerName" text="i am header paragraph!" />
{this.state.elements.map((i: any) => {
return <span key={i} >{i}</span>;
})}
</div>
);
} else {
this.printMe();
return (
<div style={myStyle} >
<Label ref={this.myRef} name="headerName" text="i am header paragraph!"/>
{this.state.elements.map((i: any) => {
return <li key={i} >{i}</li>;
})}
</div>
);
}
}
public componentDidUpdate(prevProps: any) {
// Typical usage (don't forget to compare props):
console.warn("prevProps name is: " + prevProps.name);
if (this.props.background !== prevProps.background) {
this.printMe();
} else {
console.log("Background is same no update.");
}
}
public add = (id: number, content: any, event: any ) => {
this.setState(
{
elements: [React.createElement("div", { key: 2 , onclick : null }, "tyest 12")],
visibility : false,
},
);
// tslint:disable-next-line:no-unused-expression
console.log(" add from class in state elements, visible is " , this.state.visibility );
}
public addN(event: MouseEvent | Event) {
this.setState(
{
elements: [React.createElement("div", { key: 2 , onclick : null }, "tyest 12")],
visibility : false,
},
);
// tslint:disable-next-line:no-unused-expression
console.log(" add from class in state elements, visible is NNNN " , this.state.visibility );
}
}
MAIN FILE :
const AddNewElement = Services.addNewElement;
const collectMe = <Header background="#127654"/>;
ReactDOM.render(
<>
{collectMe}
<h3>Page title - inline text only example </h3>
<Title name="title" text="Hello react title" />
<Label name="root" text="I am text label component!"/> <br/>
<TextBox name="root" text="I am textBox component!"/>
</>,
document.getElementById("root"),
);
// This space is already out of class so why i can't change it ???
collectMe.props.background = "#121212";
console.log(collectMe.props);
There is lot of problem with react js.
In this post there's methods but still not working for me :
https://www.javascriptstuff.com/component-communication/#2-instance-methods
But examples are too pure with out args passing etc...
Is it react just a commercial puffed-up project.
props are read-only.
Whether you declare a component as a function or a class, it must never modify its own props.
What you need to do here is to use state. And to use state, you need to have class based component. Then, you can update the parent component state from child component using a callback function.
Take a look at this post to update the parent state from child component.
I've got 3 components as follows and the first on change on the input field makes it lose focus. I've tried giving the input fields and divs keys but it didn't solve my problem. I'm new to React so I might be doing something basic incorrectly. I'm not creating a new function inside a render method which is the reason for most losing focus issues documented in stackoverflow. Hence the reason for the new post.
Index.tsx
import * as React from "react";
import { IQuery, Queries } from "./components/Queries/Queries";
interface IManageResponseState {
primaryQuery: IQuery;
alternateQueries: IQuery[];
}
export class ManageResponse extends React.Component<any, IManageResponseState> {
constructor(props: any) {
super(props);
this.state = {
primaryQuery: {
queryText: "This is my primary query text",
id: 0
}, alternateQueries: [{
queryText: "this is my alternate query text 1",
id: 1
},
{
queryText: "this is my alternate query text 2",
id: 2
}]
};
this.addFunc = this.addFunc.bind(this);
this.removeFunc = this.removeFunc.bind(this);
this.primaryChangedFunc = this.primaryChangedFunc.bind(this);
this.alternateChangedFunc = this.alternateChangedFunc.bind(this);
}
public addFunc(text: string) {
const newQueries = this.state.alternateQueries.filter(q => true);
newQueries.push({ id: 0, queryText: text });
this.setState({ alternateQueries: newQueries });
};
public removeFunc(index: number) {
this.setState({ alternateQueries: this.state.alternateQueries.splice(index, 1) });
console.log("Remove called:" + index);
};
public primaryChangedFunc(text: string) {
const query = {
queryText: text,
id: 0
};
this.setState({ primaryQuery: query });
console.log("changed primary called:" + text);
}
public alternateChangedFunc(index: number, text: string) {
const item = this.state.alternateQueries[index];
const newQueries = this.state.alternateQueries.filter(q => true);
newQueries[index] = {
queryText: text,
id: item.id
};
this.setState({ alternateQueries: newQueries })
console.log("changed alternate called:" + text);
}
public render() {
return (
<React.Fragment>
<Queries primaryQuery={this.state.primaryQuery} alternateQueries={this.state.alternateQueries} onAddQuery={this.addFunc} onRemoveQuery={this.removeFunc} onPrimaryChanged={this.primaryChangedFunc} onAlternateQueryChanged={this.alternateChangedFunc} />
</React.Fragment>
);
}
}
Queries.tsx
import * as classnames from 'classnames';
import * as React from "react";
import { AlternateQueryItem } from "../AlternateQueryItem/AlternateQueryItem";
import './Queries.scss'
export interface IQuery {
queryText: string;
id: number;
}
export interface IQueryProps {
primaryQuery: IQuery;
alternateQueries: IQuery[];
onPrimaryChanged: (queryText: string) => void;
onAlternateQueryChanged: (index: number, queryText: string) => void;
onAddQuery: (queryText: string) => void;
onRemoveQuery: (atIndex: number) => void;
}
interface IQueryState {
primaryQueryInvalid: boolean;
}
class Queries extends React.Component<IQueryProps, IQueryState> {
constructor(props: IQueryProps) {
super(props);
this.onPrimaryQueryChanged = this.onPrimaryQueryChanged.bind(this);
this.state = { primaryQueryInvalid: false };
}
public render() {
return (
<main className="query-main-container">
<div className="primary-query-container">
<div className="form-group">
<h5 className={classnames("primary-query-header", { 'invalid': this.state.primaryQueryInvalid })}>Primary query</h5>
<div className="primary-query">
<div>{ "hello " + this.state.primaryQueryInvalid }</div>
<input type="text" value={this.props.primaryQuery.queryText} onChange={this.onPrimaryQueryChanged} className="form-control"/>
</div>
</div>
</div>
<div>
<h5 className="query-header">Query variations</h5>
<hr />
</div>
<div className="query-container">
{this.props.alternateQueries && this.props.alternateQueries.map((q, i) => this.renderQuery(q, i))}
</div>
</main>
);
}
public renderQuery(query: IQuery, key: number) {
return (
<AlternateQueryItem onChanged={this.props.onAlternateQueryChanged} query={query} key={key} index={key} />
);
}
private onPrimaryQueryChanged = (ev: React.FormEvent<HTMLInputElement>) => {
this.setState({ primaryQueryInvalid: ev.currentTarget.value === ""})
this.props.onPrimaryChanged(ev.currentTarget.value)
}
}
export { Queries };
AlternateQueryItem.tsx
import * as React from "react";
import { IQuery } from "../Queries/Queries";
export interface IAlternateQueryProps {
query: IQuery;
onChanged: (index: number, queryText: string) => void;
index: number;
}
class AlternateQueryItem extends React.Component<IAlternateQueryProps> {
constructor(props: IAlternateQueryProps) {
super(props);
this.onItemChanged = this.onItemChanged.bind(this);
}
public render() {
return (
<div className="form-group">
<div className="alternate-query">
<input type="text" value={this.props.query.queryText} onChange={this.onItemChanged} className="form-control" />
</div>
</div>
);
}
public onItemChanged = (ev: any) => {
this.props.onChanged(this.props.index, ev.currentTarget.value)
}
}
export { AlternateQueryItem };
I have the following:
import React from 'react';
import ReactDOM from 'react-dom'
import {render} from 'react-dom';
import Forms from './forms/forms.jsx';
class Option1 extends React.Component {
render () {
return (
<p>Icon 1</p>
)
}
}
class TShirt extends React.Component {
render () {
console.log(this.props.currentState);
return <div className="thsirt">
<h1>{this.props.name}</h1>
<p>{this.props.iconID}</p>
{this.props.optionA ? <Option1 /> : ''}
</div>;
}
}
class Link extends React.Component {
render () {
return (
<li
data-id={this.props.el}
onClick={this.props.onClick}
className={this.props.activeClass}>{this.props.el}
</li>
);
}
}
class Nav extends React.Component {
getComponentID (id) {
switch(id) {
case 'name':
return 1;
break;
case 'color':
return 2;
break;
case 'design':
return 3;
break;
case 'share':
return 4;
break;
}
}
handleClick (event) {
// setting active class
var id = event.target.getAttribute("data-id");
this.props.action(id);
// switching coomponent based on active class
var component = this.getComponentID(id);
this.props.switchComponent(component);
}
render () {
var links = ['name', 'color', 'design', 'share'],
newLinks = [],
that = this;
links.forEach(function(el){
newLinks.push(<Link
onClick={that.handleClick.bind(that)}
activeClass={that.props.active == el ? 'active': ''}
key={el}
el={el}
/>
);
});
return (
<ol>
{newLinks}
</ol>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
color: '',
active: '',
formId: 1,
optionA: {
on: false,
icon_id: '',
option_id: '',
name: ''
}
};
this.setName = this.setName.bind(this);
this.setColor = this.setColor.bind(this);
this.setAtciveNavEl = this.setAtciveNavEl.bind(this);
this.setFormId = this.setFormId.bind(this);
this.setOptionA = this.setOptionA.bind(this);
this.setOptionAVisibility = this.setOptionAVisibility.bind(this);
}
setName (tshirt) {
this.setState({ name:tshirt })
}
setColor (color) {
this.setState({ color:color })
}
setAtciveNavEl (el) {
this.setState({ active:el })
}
setFormId (id) {
this.setState({ formId:id })
}
setOptionA (iconID, iconName) {
this.setState({
optionA:
{
icon_id: iconID,
name: iconName
}
})
}
setOptionAVisibility (onOff, optionID) {
this.setState({
optionA:
{
option_id: optionID,
on: onOff
}
})
}
render () {
return (
<section className={this.state.color}>
<Nav
active={this.state.active}
action={this.setAtciveNavEl}
switchComponent={this.setFormId}
/>
<TShirt
name={this.state.name}
icons={this.state.options}
optionA={this.state.optionA.on}
currentState={this.state}
/>
<Forms
name={this.state.name}
action={this.setName}
colorVal={this.setColor}
activeNav={this.setAtciveNavEl}
switchComponent={this.setFormId}
formID={this.state.formId}
setOptionA={this.setOptionA}
setOptionAVisibility={this.setOptionAVisibility}
/>
</section>
);
}
}
render(<App/>, document.getElementById('app'));
I need to populate this object at different times like this:
setOptionA (iconID, iconName) {
this.setState({
optionA:
{
icon_id: iconID,
name: iconName
}
})
}
setOptionAVisibility (onOff, optionID) {
this.setState({
optionA:
{
option_id: optionID,
on: onOff
}
})
}
The problem I have is taht when I console.log my state at:
class TShirt extends React.Component {
render () {
console.log(this.props.currentState);
return <div className="thsirt">
<h1>{this.props.name}</h1>
<p>{this.props.iconID}</p>
{this.props.optionA ? <Option1 /> : ''}
</div>;
}
}
after all my click events it seems like I loose the "on" and "option_id" from the optionA object.
Does calling setState on the same object override the previous setState?
If you are writing ES2015, you can use the spread operator to copy the whole object and just modify one of it's properties:
setOptionAVisibility (onOff, optionID) {
this.setState({
optionA:
{
...this.state.optionA,
option_id: optionID,
on: onOff
}
})
}
Can be very useful when modifying single properties of complex objects on the state tree.