How to access the index of a MaterialUI StepConnector - reactjs

I am using a Stepper component, and I would like to style the connectors individually based on their index. The need to be able to access the index of the current step from within StepConnector came up in this GitHub issue in February, and a PR was accepted to make this easy with useStepContext. I'm using the current version of MaterialUI, 5.10.4.
However, I'm getting an empty object back instead of the context I'm expecting with the index. This happens with both approaches. The only difference I can see between what I'm doing and the sample code from the GitHub issue is that I'm on 5.10.4 and the sample is using 5.4.0. But perhaps I'm missing something?
Here is my code. The easy way:
import { useStepContext } from "#mui/material/Step/StepContext";
import StepConnector from "#mui/material/StepConnector";
function CIConnector(props) {
const ctx = useStepContext();
console.log("context:", ctx);
return (
<StepConnector />
);
}
The hard way, suggested as a workaround in the original issue before the PR was accepted:
import * as React from "react";
import StepContext from "#mui/material/Step/StepContext";
import StepConnector from "#mui/material/StepConnector";
function CIConnector(props) {
const ctx = React.useContext(StepContext);
console.log("context:", ctx);
return (
<StepConnector />
);
}
In this second version, when I break in the debugger, StepContext is undefined. But if I step into useContext(), it seems to correctly receive the StepContext object. Still, it's returning an empty object.
What am I doing wrong?
I have gotten a minimal test to fail too, so I have opened a bug with MUI.

The problem was the way I was importing the method. This code works on MaterialUI 5.10.17:
import { StepConnector, useStepContext } from "#mui/material/Step";
function CIConnector(props) {
const ctx = useStepContext();
console.log("context:", ctx);
return (
<StepConnector />
);
}

Related

Typescript useState React Hook Destructuring Error (Not Returning Array?)

I'm futzing about with a simple React app for the first time, and looking to set up a simple MVC to connect with an ASP.NET backend, all being done in Visual Studio 2019 (which has caused some headaches with React). However, now that I'm trying to implement models, I'm finding that all of the suggestions for strongly typing the useState hook aren't working for me.
According to a few tutorials like this one or this one, it should be as simple as adding a type in brackets, like const [state, setState] = useState<Type>({}), since it has a generic implementation. Unfortunately, for me, this throws the error "Uncaught TypeError: Invalid attempt to destructure non-iterable instance."
This thread here suggested that switching from an array to an object by changing the [] to {}, however that simply made the two parameters I passed be undefined, so I had no state or way to update said state.
I went down the path of reading until I had a brief understanding of array destructuring, so I understand that the idea is to pass an array with two constants that will be assigned in-order the elements of the array returned by the useState hook. So, I tried manually destructuring the array, setting a constant useState[0] and useState[1] separately. When I tried this for an untyped hook, it worked as expected. When I tried this for the typed hook, I got some errors about there not being elements, and upon printing out the object, found not an array like the untyped hook, but a boolean. It seems that a typed useState is returning the value "false" instead of an array.
At this point, my best guess is that I have some dependencies that don't implement the typed useState, but I'm really hitting a stone wall on troubleshooting. Anyone have some idea on what I'm doing wrong?
Edit: The testing file I have set-up -
import React, { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Product } from '../Models/Product';
const Account = () => {
//Works as-intended
const test = useState(5);
//Returns false when logged
const test2 = useState<Product>({
"ProductID": "p#corn", "Description": "Delicious corn", "ImageLink": "https://testlink.com", "Name": "Corn", "Price": "2.99", "Category": "Food"
});
//What should work, to my understanding, however this makes the route crash when it's navigated to because of the "Inavlid attempt to destructure non-iterable instance
const [test3, setTest] = useState<Product>({});
function clickHandler() {
console.log(test)
}
function clickHandler2() {
console.log(test2)
}
return (
<div className='wrapper'>
<button onClick={clickHandler}>Test</button>
<button onClick={clickHandler2}>Test2</button>
</div>
)
}
export default Account;
The Product model -
export interface Product {
ProductID: string;
Description: string;
ImageLink: string;
Name: string;
Price: string;
Category: string;
}
Here's a CodeSandbox with an example somewhat related to your case, which demonstrates how useState is meant to work on everyone else's machine.
As you will see from testing it and messing with the example I shared, useState with a generic type specified should be fine and dandy and behave just as you expect.
That underlines that there's something about your local machine or project environment which is special to you.
import React, { useCallback, useState } from "react";
import "./styles.css";
interface Product {
Name: string;
Price: number;
}
const productA = {
Name: "Corn",
Price: 2.99
};
const productB = {
Name: "Frozen Orange Juice",
Price: 10_000
};
export default function Show() {
const [product, setProduct] = useState<Product>(productA);
const toggleProduct = () =>
setProduct(product === productA ? productB : productA);
return (
<div className="App" onClick={toggleProduct}>
<h1>{product.Name}</h1>
<h2>{product.Price}</h2>
</div>
);
}
Since you asked about how to get the best responses...
Ideally when posting try to create a problem case which other people can see failing. If you attempt to do this (e.g. using a CodeSandbox) but it works fine there, then it's a matter of working on cleaning up your own local environment until you figure out what is unique about your setup which makes code break for you but no-one else.
Ideally if you can't create it within a single page repro (sandbox), because it's something to do with your project structure, create a runnable reproduction by sharing the actual project structure and its code and configuration publically on github so people can recreate your problem by checking it out and building/running it. That way they will soon be able to track down what's distinctive about your project.
Often this process of creating a repro will help you figure out the problem anyway - e.g. you start with a vanilla create-react-app typescript skeleton from https://create-react-app.dev/docs/adding-typescript/ to populate a blank github repo and your problem case suddenly starts working there - now you have a basis for bisecting your problem by adding your project's special features to the simple repro until it breaks.

Im using mobx 5.15.7 seeing weird behavior

Hello I am use to mobx 4 just getting to mobx 5 and I noticed that the syntax and someways you read observable variables have changed I am trying to log to the console.log the output of some data Im getting from a route, but I am seeing a Proxy and some other stuff. Screenshots are posted below and an explanation would be be greatly appreciated.
Here is what I have some far code wise.
const { team } = this.props.teamStore;
console.log(this.props.teamStore)
const userTeams = !!team ? team : null;
console.log(userTeams)
return (
<div className="text-center mt-40">
<div>Home page again lets get it.</div>
{this.getTeams()}
</div>
);
Here is the weird output I was experincing
[[Handler]]: Object
[[Target]]: Array(3)
[[IsRevoked]]: false
This is normal, MobX 5 uses Proxy under the the hood (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), and this is what it does to your observable data.
You can try to use toJS method on your data if you want regular console output, like that:
import { toJS } from 'mobx';
// ...
console.log(toJS(userTeams))
More here: https://www.mobxjs.com/refguide/tojson.html

Can Someone help me to convert typescript code to React Code

There is a package called react-data-grid. And there is an example table on that particular package but the code is in TypeScript and also docs for this particular version are not there. I tried to convert the typescript to React. Everything was fine until I wanted to implement Drag and Drop. Some error is coming and I think that error is because I'm importing something in the wrong way. Can you tell me where I'm doing anything wrong?
Here is the Sandbox link.
The error in my local build is coming on RowRender.js in line number 44.
I also included the typescript file there.
You can also see the error if you just uncomment the line 72-74 of App.js component in sandbox.
Rename .ts file to .tsx file. In another case TypeScript will not understand <div> <Row> and other react elements
Update your imports regarding react-data-grid to: import { Row, RowRendererProps } from "react-data-grid";
Update your import import { useCombinedRefs } from ... to fetch hook from correct place.
If you will see error regarding default import for React - change import React from 'react' to import * as React from "react"; or update tsconfig to support synthetic imports
useCombinedRefs - is internal function that is not exported, so you can't use it directly. Option #1 - write it yourself. Option #2 find the reason why you are trying to use internal function. Should be the better way.
function useCombinedRefs(...refs) {
return useCallback(handle => {
for (const ref of refs) {
if (typeof ref === 'function') {
ref(handle);
} else if (ref !== null) {
ref.current = handle;
}
}
}, refs);
}

Is there a problem in 'react-metismenu-router-link' with react16?

in the use of library 'react-metismenu' there is not problem and work correctly,but this use anchor for selecting item of menu. that is not good.
so to use react-router-link i use 'react-metismenu-router-link' library
but this error accured:(
Cannot read property 'history' of undefined
this.context.router.history.listen(this.onLocationChange.bind(this));
how to fix this problem?
https://www.npmjs.com/package/react-metismenu-router-link
There's an open PR to fix this bug but the original repository has been archived so it won't be merged.
You can checkout jhillhouse92's fork of react-metismenu-router-link and install this package instead of the original one, it includes the code of the PR.
Edit: I'm adding more information as suggested.
This bug is caused by the use of Context API instead of props in RouterLink component, as you can see in the PR.
These are the bug causing lines in RouterLink.jsx :
this.context.router.history.listen(this.onLocationChange.bind(this));
this.onLocationChange(this.context.router.route);
jhillhouse92 commits are replacing context with props:
class RouterLink extends React.Component {
componentWillMount() {
this.to = this.props.to;
if (this.to[0] !== '/') this.to = `/${this.to}`;
// He is using props.history instead of context.router.history
// and props.location instead of context.router.route
this.props.history.listen(this.onLocationChange.bind(this));
this.onLocationChange(this.props.location);
}
onLocationChange(e) {
if ((e.pathname || '/') === this.to) {
this.props.activateMe();
}
}
We are also adding withRouter in the export of our RouterLink component to give him react-router-dom related props (e.g. props.history):
export default withRouter(RouterLink);
Applying these changes, either by installing the package from git or editing manually should solve your bug.

What is Reacts function for checking if a property applies?

Based off this Q&A:
React wrapper: React does not recognize the `staticContext` prop on a DOM element
The answer is not great for my scenario, I have a lot of props and really dislike copy-pasting with hopes whoever touches the code next updates both.
So, what I think might work is just re-purposing whatever function it is that React uses to check if a property fits to conditionally remove properties before submitting.
Something like this:
import { imaginaryIsDomAttributeFn } from "react"
...
render() {
const tooManyProps = this.props;
const justTheRightProps = {} as any;
Object.keys(tooManyProps).forEach((key) => {
if (imaginaryIsDomAttributeFn(key) === false) { return; }
justTheRightProps[key] = tooManyProps[key];
});
return <div {...justTheRightProps} />
}
I have found the DOMAttributes and HTMLAttributes in Reacts index.t.ts, and could potentially turn them into a massive array of strings to check the keys against, but... I'd rather have that as a last resort.
So, How does React do the check? And can I reuse their code for it?
The following isn't meant to be a complete answer, but something helpful for you in case I forget to come back to this post. The following code is working so far.
// reacts special properties
const SPECIAL_PROPS = [
"key",
"children",
"dangerouslySetInnerHTML",
];
// test if the property exists on a div in either given case, or lower case
// eg (onClick vs onclick)
const testDiv = document.createElement("div");
function isDomElementProp(propName: string) {
return (propName in testDiv) || (propName.toLowerCase() in testDiv) || SPECIAL_PROPS.includes(propName);
}
The React internal function to validate property names is located here: https://github.com/facebook/react/blob/master/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js
The main thing it checks the properties against is a "possibleStandardNames" property-list here: https://github.com/facebook/react/blob/master/packages/react-dom/src/shared/possibleStandardNames.js
So to reuse their code, you can copy the property-list in possibleStandardNames.js into your project, then use it to filter out properties that aren't listed there.

Resources