Problem with acces to function with react javascript child component - javascript

They would like to function from the component from the child component. This method call: TypeError: Pizza__WEBPACK_IMPORTED_MODULE_2_.default.valid is not a function.
I try to add static function but it will not get the value.
I can add code of pizza to orders, but this not I will.
Can anyone help?
I want to get dish_details from Pizza and Show Pizza form underneath.
In .js no .tsx
Parend class:
class Orders extends React.Component {
constructor(props) {
super(props);
this.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
kind(){
switch (this.order.type) {
case 'pizza':
return <Pizza/>;
}
}
submit(){
console.log(Pizza.dishDetails()); // return error
}
render() {
return (<div>
<div>{this.state.selected ? this.kind() : ""}</div>
<button className={styles.order_submit} onClick={this.submit.bind(this)}>Submit</button>
</div>
);
}
Kids class:
class Pizza extends React.Component{
constructor(props) {
super(props);
this.state = {
noOfSlices : 0,
diameter : 0
}
}
dishDetails(){
return this.state;
}
noOfSlices(e){
this.setState({noOfSlices : e.target.value});
}

If you want your components to have a state you need to declare it with
this.state.[the name of the variable]
That's how react knows that you want to store state inside a component. The error you get probably is because you declared the state of the pizza component wrongly
dish_details = { //Not correct
noOfSlices : 0,
diameter : 0
}
Here you declare it inside the constructor, and that is correct, but in order to work you need to use the component state.
constructor(props) { /
super(props);
this.state.order = {
name: "",
preparation_time: "00:00:00",
type: "",
}
}
Check out the docs on state.

You have several issues here
you say something is static, but you have not created a static function!
submit(){
console.log(Pizza.dishDetails()); // return error or undefined when static
}
This is a call to a static function. To create a static function you would do this:
// ES5
Pizza.dishDetails = function(){ /* do something that does not touch `this` */ }
or in modern ES2015+:
class Pizza {
static dishDetailsfunction(){
/* do something that does not touch `this` */
}
}
The dishDetailsfunction function is not static, but more importantly, it cannot be static, since it uses this. A static function has no reference to this - that's the definition of static.
So you need to reorganize a bit ...
You are not allowed to access the inner state of a component from an outer component, so you need to either do your data and external actions handling outside of your components (like Redux), use some kind of callback logic, or delegate the logic for handling submits down to Pizza.
Here is one way to do it using a callback:
In the order component
renderPizza() {
// the `this` in the callback references the Orders (parent) component
return <Pizza onChange={(pizzaOrder) => this.setState({order: pizzaOrder}) }/>} />
}
In the pizza component:
updateNoOfSlices(e){
this.setState({noOfSlices : e.target.value});
this.prop.onChange({this.state});
}
I removed all the logic that is not necessary for the point, but you should see how a callback solves this easily.
P.S. If you centralize your data handling in one place (for instance a component) you will get simpler and more easily testable code. For instance, you can remove all state from the Pizza class and just let it have noOfSlices and diameter passed to it as props from the Orders class.

I have answer. I create clas Static with static value, and this is working for me.
static
class Static {
static defaultProps = {}
}
export default Static;
order
submit(){
console.log(Static.defaultProps)
pizza
noOfSlices(e){
Static.defaultProps = {noOfSlices : e.target.value};
}

Related

Function to get object from list of implementations in class by type of implementation. (typescript generics)

I have a list of Components in a class Entity. These components extend the interface Component.
class Entity {
...
const components: Component[] = [];
...
}
Where specific components implements the interface Component
class SpecificComponent0 implements Component { ... }
Now I want to query the entity instance e and get a component if it matches the type fed into the query, something like this:
const specificComponent0 = e.getSpecificComponent<SpecificComponentClass0>();
Or perhaps like this
const specificComponent0 = e.getSpecificComponent(instanceof SpecificComponentClass0)
But I can't seem to figure out a way to do it in the entity's get function.
This is a tricky one as you are mixing runtime and build-time concerns. Referring to the examples you suggested:
const specificComponent0 = e.getSpecificComponent<SpecificComponentClass0>();
This definitely isn't going to work, because the angle brackets specify a "Type Parameter", which only exists at build time. Since what you are trying to do involves logic, you need to pass something into the function at runtime to help it pick the correct element.
const specificComponent0 = e.getSpecificComponent(instanceof SpecificComponentClass0)
The return value of the instanceof operator is a boolean value. You are passing either true or false into this function, which isn't very useful.
You have two problems here.
You want to pass something into the function that will allow you to select the right component
I am assuming you want the function to return a component narrowed to the correct type, rather than typed generically as Component
Problem 1 can be solved by passing in the type Constructor function and then matching it with the constructor property of the instantiated Component
class Entity {
constructor(private components: Component[]) {}
getSpecificComponent(thing: new () => Component): Component | undefined {
return this.components.find(component => component.constructor === thing)
}
}
This works perfectly fine, but your getSpecificComponent function is going to return a value typed as Component | undefined, which isn't very useful if you want to use properties that only exist on one of the specific types.
To solve Problem 2 (without casting the return value, which you really shouldn't do), we need to
Make the function generic and
Turn the predicate that is passed into find into a user defined type guard to give the compiler a hint that if that function returns true, it can safely narrow the type down to the generic type
class Component {}
class OtherThing1 extends Component { name = 'thing1' }
class OtherThing2 extends Component { name = 'thing2' }
class OtherThing3 extends Component { name = 'thing3' }
const getNarrower = <T extends Component>(thingConstructor: new () => T) =>
(thing: Component): thing is T => thing.constructor === thingConstructor
class Entity {
constructor(private components: Component[]) {}
getSpecificComponent<T extends Component>(thing: new () => T): T | undefined {
return this.components.find(getNarrower(thing))
}
}
const e = new Entity([new OtherThing1(), new OtherThing2()])
const thing = e.getSpecificComponent(OtherThing1)
console.log(thing) // [LOG]: OtherThing1: { "name": "thing1" }
const thingNotHere = e.getSpecificComponent(OtherThing3)
console.log(thingNotHere) // [LOG]: undefined

React child component receives object. Why there is no visual update upon change of just one attribute of the object?

I have a Javascript complex data structure with 2 person fields - customer and payer (both are of type Person)
{
invoice: {
id: 123,
warehouseId: 456;
customer: {
id: 777,
name: "Coco"
}
payer: {
id: 778,
name: "Roro"
}
}
}
I am using child component for displaying Person object:
class ConnectedPersonFieldSet extends Component {
render () {
return
<div>
<div>{this.props.label}</div>
<div>{this.props.data.id}</div>
<div>{this.props.data.name}</div>
</div>
}
}
const PersonFieldSet = connect(mapStateToProps, mapDispatchToProps)(ConnectedPersonFieldSet);
export default PersonFieldSet;
And I have parent component that display full Invoice object and which has 2 child components for customer and payer respectively:
class ConnectedInvoice extends Component {
render () {
return
<div>
<div>{this.props.invoice.id}</div>
<div>{this.props.invoice.warehouseId}</div>
<PersonFieldSet label={"Customer" + /* this.props.customer.name */ } data={this.props.customer}></PersonFieldSet>
<PersonFieldSet label="Payer" data={this.props.payer}></PersonFieldSet>
</div>
}
}
const Invoice = connect(mapStateToProps, mapDispatchToProps)(ConnectedInvoice);
export default Invoice;
I have also complex logic that changes just invoice.customer.name. The updated customer name becomes visible in the Invoice component:
<div>{this.props.invoice.id}</div>
But, unfortunately, the
<PersonFieldSet label={"Customer" + /* this.props.customer.name */ } data={this.props.customer}></PersonFieldSet>
stays the same. If I uncomment /* this.props.customer.name */ then the updated customer.name becomes visible both in the label and in the name subcomponent of the PersonFieldSet.
So - my question is - why the child component, which receives the object, can not detect the change of the one attribute of this object and hence, does not update visual data upon the change of the one attribute of the object?
If the child component is able to feel somehow (e.g. via label={"..." + this.props.customer.name}) that the update of the attribute happened, then the child component displays the full update of all the attributes.
How to press the child component to detect that attributes can change the forwarded object?
I have read (e.g. React: why child component doesn't update when prop changes) that there is a trick with (more or less redundant) key attribute of the child element, but is this really my case?
My understanding is that React should support the hierarchical composition of both visual components and data components and do it without tricks or any other intrigues, but how to handle my situation? Should I really start to use hacks (key or others) in this situation that is pretty standard?
Added:
I am using Redux architecture for making updates - currently I am testing update of just one field - name:
const rootReducer = (state = initialState, action) => {
switch(action.type) {
case UPDATE_INVOICE_CUSTOMER: {
let person_id = action.payload.person_id;
let data = {
invoice: state.invoice
}
let newData = updateInvoiceByCustomer(data, person_id);
return {...state,
invoice: newData.invoice,
}
}
}
}
export function updateInvoiceByCustomer(data, person_id) {
let newData = {
invoice: data.invoice,
}
/* This will be replaced by the complex business logic, that retrieves
customer from the database using person_id and afterwards complex
calculations are done on the invoice, e.g. discounts and taxes
are assigned according to the rules relevant for the specific
customer. Possible all this code will have to be moved to the chain
of promises */
newData.invoice.customer.name='Test';
return newData;
}
Thanks #Yoshi for comments on my question and for persisting to check my Redux update logic. Indeed, when I have removed all the copying-update logic (which should be corrected to use cloning) and replaced it by:
return {
...state,
['invoice']: {...state['invoice'],
['customer']: {...state['invoice']['customer'],
['name']: 'REAL-TEST',
}
}
}
Then child component started to re-render and to show the actual value without any hacks or use of key-attributes. So, that was the cause of error.

typescript + react - mixed variable in state

I have this code in my react application, as per interface, a variable items should be an array.
But, in my initial state, there it is initialized as null (for I need as null as initial state).
Within the interface declaration I could have written ?Array, but it would mean, that the key items may not be in the state at all - and provided that this key is present within the object, it is going to be an array.
What are options? Is my architecture bad? Or how to declare required variable as mixed array|null?
declare interface StateInterface {
items: Array
}
class MyComponent extends Component {
state: StateInterface = {
items: null
};
}
You could initialize it to an empty array:
class MyComponent extends Component<{}, StateInterface> {
constructor() {
this.state = { items: [] };
}
}

Reusing code across React component

I have a bunch of components with methods like these
class Header extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
I'd like to move this duplicate code to a function such as
function toggleBodyClass(className, e) {
e.preventDefault();
document.body.classList.toggle('sidebar-mobile-show');
}
Then refactor the functions above like so
sidebarMinimize(e) {
toggleBodyClass('sidebar-minimized', e);
}
In the past, I would have used a mixin, but the React docs now discourage their use.
Should I just put this function in a regular JavaScript module and import it in the component modules, or is there a particular React construct for reusing code across components?
You could make a High Order Component with those functions as so:
import React, { Component } from 'react';
export default function(ComposedComponent) {
return class ExampleHOC extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
render()
return <ComposedComponent { ...this.props } />;
}
}
}
Then take whatever component you wish to augment with those properties by wrapping them in the HOC:
ExampleHOC(Header);
Should I just put this function in a regular JavaScript module and import it in the component modules
Yes. That would be a pretty standard way to share code between JavaScript files. I don't believe you need to or should do anything React-related to achieve this.
However, it is important to understand that you shouldn't directly interact with the DOM ever from a React component. Thanks #ShubhamKhatri for the heads up.
In my opinion, you are correct in putting the function in a regular JavaScript module and import it in the component modules.
Since a typical answer OOP answer would be to create another class extending React.Component adding that function. Then extend that class so every component you create will have that function but React doesn't want that.
One thing to verify that you are correct is in this pattern I believe.
https://reactjs.org/docs/composition-vs-inheritance.html
inherence solve your problem , create new class that extends Component and extend from your new class to share functionality and reduce the code
class SuperComponent extends Component
{
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
---------------------------------------------------------------------
class Home extends SuperComponent
{
someMethod()
{
this.sidebarMinimize();
}
}
class Main extends SuperComponent
{
someMethod()
{
this.sidebarToggle();
}
}
Other Solution
create utils class and use it in your component
class UIUtiles
{
static sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
static sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
class Home extends SuperComponent {
someMethod(e) {
UIUtiles.sidebarToggle(e);
UIUtiles.sidebarMinimize(e);
}
}

How to override a parent class method in React?

I'm extending a base class and overriding a method in the base class. But when I call it, it calls the super class version. How do I override the method?
var Hello = React.createClass( {
getName: function() { return "super" },
render: function() {
return <div>This is: {this.getName()}</div>;
}
});
class HelloChild extends Hello {
constructor(props) {
super(props);
console.log( this.getName());
}
getName()
{
return "Child";
}
};
I want it to print "This is: Child" but it prints "This is: super"
The problem is that you're mixing ES6 type class declaration (ex. Hello) with old school Javascript declaration (ex. HelloChild). To fix HelloChild, bind the method to the class.
class HelloChild extends Hello {
constructor(props) {
super(props);
this.getName = this.getName.bind(this); // This is important
console.log( this.getName());
}
getName()
{
return "Child";
}
};
Then it'll work.
I found the answer (adapted from here: https://gist.github.com/Zodiase/af44115098b20d69c531 ) - the base class needs to also be defined in an ES6 manner:
class Hello extends React.Component {
//abstract getName()
getName()
{
if (new.target === Hello) {
throw new TypeError("method not implemented");
}
}
render() {
return <div>This is: {this.getName()}</div>;
}
};
Actually you can override method to execute code from your subclass
class Hello extends React.Component {
getName() {
super.getName();
}
}
class HelloChild extends Hello {
getName()
{
return "Child";
}
}
Please note that this answer proposes different approach:
I wonder why you should do this in the first place, my point is that directly coupling two react components is not a right way to implement re-usability in React.
If you are trying to have multiple child components which extends one parent, What I would do is, to have child components and a higher-order component and then implement common functionality with Composition. This way you can skip those methods, which you were trying to override and so everything would stay clear.

Categories