Use destructuring assignment inside state - reactjs

class BottomPanelProgramTabs extends React.Component<Props, State> {
state = {
activeTab: this.props.children[0].props.label,
};
...
ESLint want me to use destructuring assignment on
this.props.children[0].props.label
any ideas on how to do that?

you can do like this.
For more reference about prefer-destructuring
class BottomPanelProgramTabs extends React.Component<Props, State> {
constructor(){
let [props] = this.props.children;
state = {
activeTab : props.label
}
}

class BottomPanelProgramTabs extends React.Component<Props, State> {
state = {
activeTab: 'default label'
};
componentDidMount = () => {
const [{ props: { label } }] = this.props.children;
this.setState({
activeTab: label || 'default label',
...
})
}
...
You can mix destructing by getting the first element with [] and get the props with {}.
For example:
using [child] will give us the first element in the array.
const children = [{
props: {
label: 'Some label'
}
},
{
props: {
label: 'Second label'
}
},
,
{
props: {
label: 'another label'
}
}]
const [child] = children;
console.log(child);
to get props we can continue mixing our destruction by adding [ {props} ] which returns props object.
const children = [{
props: {
label: 'Some label'
}
},
{
props: {
label: 'Second label'
}
},
,
{
props: {
label: 'another label'
}
}]
const [ {props} ] = children;
console.log(props);
to get the label from props will can do this [{ props: { label } }]
const children = [{
props: {
label: 'Some label'
}
},
{
props: {
label: 'Second label'
}
},
,
{
props: {
label: 'another label'
}
}]
const [{ props: { label } }] = children;
console.log(label);
With complex data
const children = [{
props: {
label: [{
data: {
title: 'complex destructor'
}
},
{
data: {
title: 'complex destructor 2'
}
}]
}
},
{
props: {
label: 'Second label'
}
},
,
{
props: {
label: 'another label'
}
}]
const [{ props: { label: [ { data: { title } } ] } }] = children;
console.log(title)

Related

How to update nested state in redux

I'm a bit stuck with redux. I want to create reducer that can update state onClick with data that provided in each button.
Here's my TabSlice.ts
interface ITabContext {
tabIndex: number,
posterUrlFetch: string,
tabData: {
fetchUrl: string;
title: string;
}[]
}
const initialState = {
tabIndex: 0,
posterUrlFetch: 'movie/popular',
tabData: [
{ fetchUrl: 'movie/popular', title: 'Trending' },
{ fetchUrl: 'movie/upcoming', title: 'Upcoming' },
{ fetchUrl: 'tv/popular', title: 'TV Series' },
]
}
const tabSlice = createSlice({
name: 'tab',
initialState: initialState as ITabContext,
reducers: {
changeTab(state, action: PayloadAction<ITab>) {
const newItem = action.payload;
return state = {
tabIndex: newItem.tabIndex,
posterUrlFetch: newItem.posterUrlFetch,
tabData: [
{ fetchUrl: newItem.posterUrlFetch, title: newItem.posterUrlFetch },
]
}
}
}
})
Then I dispatch changeTab in my component and create function onClick:
const click = () => dispatch(changeTab({
tabIndex: 1,
posterUrlFetch: 'movie/popular',
tabData: [
{
fetchUrl: 'tv/latest',
title: 'TV Latest'
},
{
fetchUrl: 'movie/popular',
title: 'Popular'
},
{
fetchUrl: 'movie/latest',
title: 'Latest'
},
]
}));
As i click some info updates, but in tabData I have only first object. How to make it to push all data to tabData, not only first one? Thanks!
Remove return state = {} from your reducer function and instead return the object as a whole.
return {
tabIndex: newItem.tabIndex,
posterUrlFetch: newItem.posterUrlFetch,
tabData: newItem.tabData,
};
For the payload's tabData you can pass newItem.tabData

State exists but not a function error happens. this.setState is not a function

State is existing but "not a function error" happens.
I am developing a component with React Tag.
The function is exists
I have no idea what it is wrong..
Error says
TypeError: this.setState is not a function
class ReagtTagSample extends Component {
constructor(props) {
super(props);
this.state = {
tags: [{ id: 'Yugoslavia', text: 'Yugoslavia' }, { id: 'India', text: 'India' }],
suggestions: [
{ id: "England", text: "England" },
{ id: "Mexico", text: "Mexico" },
],
};
handleAddition(tag) {
this.setState((state) => ({ tags: [...state.tags, tag] }));
}
handleDrag(tag, currPos, newPos) {
const tags = [...this.state.tags];
const newTags = tags.slice();
newTags.splice(currPos, 1);
newTags.splice(newPos, 0, tag);
this.setState({ tags: newTags });
}
render() {
const { test } = this.props;
const { tags, suggestions } = this.state;
<ReactTags
tags={tags}
suggestions={suggestions}
handleDelete={this.handleDelete}
handleAddition={this.handleAddition}
handleDrag={this.handleDrag}
delimiters={delimiters}
/>
handleAddition should be an arrow function to rebind this otherwise is not a class reference
handleAddition = (tag) => {
this.setState((state) => ({ tags: [...state.tags, tag] }));
}
same applies for handleDrag

Updating React-Select menu with setState?

I am trying to get React-Select to display a different dropdown menu list based on the user input:
const helpOptions = [
{ value: "user", label: "u:<String> User Operator" },
{ value: "day", label: "d:<Number> Date Operator" },
{ value: "week", label: "w:<Number> Week Operator" },
{ value: "month", label: "m:<Number> Month Operator" },
{ value: "bracket", label: "() Brackets Operator" },
{ value: "and", label: "&& AND Operator" },
{ value: "or", label: "|| OR Operator" },
{ value: "not", label: "~ NOT Operator" }
];
const userOptions = [
{ value: "john", label: "u:John" },
];
class Field extends Component {
state = {
menu: userOptions,
value: ""
};
onInputChange = e => {
if (e.substring(0, 1) === "?") {
this.setState(
{
menu: helpOptions,
value: e
},
() => {
console.log(this.state.menu);
}
);
} else {
this.setState({
menu: []
});
}
};
render() {
const { menu, value } = this.state;
console.log("rendering");
console.log(menu);
return (
<Select
isMulti
value={value}
options={menu}
onInputChange={this.onInputChange}
/>
);
}
}
The desired behavior is if the first character of the text entered into the search field is a '?' the menu will populate with the const of helpOptions. Otherwise it would be (for now) empty.
Codesandbox: https://codesandbox.io/s/runtime-sun-cfg71
From the console logs, I seem to be getting the values and the rendering seems to be working. However, I am still getting 'No Option' as a response from the React-Select component.
How can I dynamically change the React-Select menu items based on the user's input?
Update
If you want your state to update after calling setState you need use a function that will work only after updating the state:
this.setState(state => ({
...state,
menu: helpOptions
}));
First of all you need to call a constructor in your component. Secondly, in documentation to react-select prop value doesn't exist. Thirdly, it’s good practice to copy your state before changing.
Here is a valid code:
import React, { Component } from "react";
import Select from "react-select";
import "./styles.css";
const helpOptions = [
{ value: "user", label: "u:<String> User Operator" },
{ value: "day", label: "d:<Number> Date Operator" },
{ value: "week", label: "w:<Number> Week Operator" },
{ value: "month", label: "m:<Number> Month Operator" },
{ value: "bracket", label: "() Brackets Operator" },
{ value: "and", label: "&& AND Operator" },
{ value: "or", label: "|| OR Operator" },
{ value: "not", label: "~ NOT Operator" }
];
const userOptions = [
{ value: "john", label: "u:John" },
{ value: "stan", label: "d:Stan" },
{ value: "addison", label: "w:Addison" },
{ value: "dionis", label: "m:Dionis" }
];
class Field extends Component {
constructor(props) {
super(props);
this.state = {
menu: userOptions,
value: ""
};
}
onInputChange = e => {
if (e.substring(0, 1) === "?") {
console.log("help");
this.setState({
...this.state,
menu: helpOptions
});
} else {
this.setState({
...this.state,
menu: userOptions
});
}
};
render() {
const { menu, value } = this.state;
return <Select isMulti options={menu} onInputChange={this.onInputChange} />;
}
}
export default Field;
Here is an example on codesandbox.

How do you set the value of a TextField from Dropdown Selection?

In the following code, I was curious as to how you would set the value of the following TextField.
For this example, how do I set the TextField to the selected item in the Dropdown?
If the user selects "TOP LEVEL" in the Dropdown, then I want to populate the TextField to be "TOP LEVEL". The Dropdown is called ChildComponent
import * as React from "react";
import ChildComponent from './Operations/ChildComponent';
import { DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { TextField} from 'office-ui-fabric-react/lib/TextField';
export interface ParentComponentState {
selectedItem?: { key: string | number | undefined };
value: {key: string};
}
export default class ParentComponent extends React.Component<{}, ParentComponentState> {
constructor(props, context) {
super(props, context);
}
public state: ParentComponentState = {
selectedItem: undefined,
value: undefined,
};
render(){
const { selectedItem } = this.state;
const options: IDropdownOption[] = [
{ key: 'blank', text: '' },
{ key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
{ key: 'topLevel', text: 'TOP LEVEL' },
{ key: 'make', text: 'MAKE ITEM' },
{ key: 'divider_1', text: '-', itemType: DropdownMenuItemType.Divider },
{ key: 'Purchased', text: 'Purchases', itemType: DropdownMenuItemType.Header },
{ key: 'rawMaterial', text: 'RAW MATERIAL' },
{ key: 'buyItem', text: 'BUY ITEM' },
];
return(
<div>
<ChildComponent
options={options}
selectedKey={selectedItem ? selectedItem.key : undefined}
onChange={this._onChange}
/>
<TextField
name="textTest"
label={"Test"}
/>
</div>
);
}
private _onChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
this.setState({ selectedItem: item });
let opValue = item.text;
console.log(event);
console.log(opValue);
};
}
After inserting Muhammad's logic, here is the error I am getting. Do I need to add an onChange event for the TextField? and then put "this.state.selectedItem" in the handleChange event? Do I need to make a new child component and have the TextField rollup to ParentComponent?
You just need to assign that state in the value prop for the textField as you have the selectedItem in your state
<TextFieid
label={"Test"}
styles={{ root: { width: 300 } }}
value={this.state.selectedItem}
/>
import * as React from "react";
import ChildComponent from './Operations/ChildComponent';
import { DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { TextField} from 'office-ui-fabric-react/lib/TextField';
export interface ParentComponentState {
selectedItem?: { key: string | number | undefined };
value?;
}
export default class ParentComponent extends React.Component{
constructor(props) {
super(props);
this.state = {
value: '',
};
}
public state: ParentComponentState = {
selectedItem: undefined,
};
handleChange = (event) => {
this.setState({
value: event.target.value,
})
};
render(){
const { selectedItem } = this.state;
const options: IDropdownOption[] = [
{ key: 'blank', text: '' },
{ key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
{ key: 'topLevel', text: 'TOP LEVEL' },
{ key: 'make', text: 'MAKE ITEM' },
{ key: 'divider_1', text: '-', itemType: DropdownMenuItemType.Divider },
{ key: 'Purchased', text: 'Purchases', itemType: DropdownMenuItemType.Header },
{ key: 'rawMaterial', text: 'RAW MATERIAL' },
{ key: 'buyItem', text: 'BUY ITEM' },
];
return(
<div>
<ChildComponent
options={options}
selectedKey={selectedItem ? selectedItem.key : undefined}
onChange={this._onChange}
/>
<TextField
name="textTest"
label={"Test"}
onChange={this.handleChange}
value={this.state.value}
/>
</div>
);
}
private _onChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
this.setState({ selectedItem: item });
this.setState({value: item.text})
let opValue = item.text;
console.log(event);
console.log(opValue);
};
}

Cannot change hidden column state from true to false on setState

I'm using devexpress React table and you can hide and show columns via state.
I would like to change the state for hidden from true to false but I get an Uncaught Invariant Violation error.
I've tried to use setState but doesn't work.
class ResultsTable extends Component {
constructor(props) {
super(props);
this.state = {
columns: [
{ name: 'agent', title: 'Agent' },
{ name: 'alertGroup', title: 'Alert Group', hidden:true },
{ name: 'manager', title: 'Manager', hidden:true }
],
};
}
componentDidMount() {
this.testAlert();
}
testAlert = () => {
if (this.props.alertgroupColumn()) {
this.setState({
columns: [{ name: 'alertGroup', title: 'Alert Group', hidden:false }]
})
}
}
Hidden should change from true to false.
I have another alternative to update your state
class ResultsTable extends Component {
constructor(props) {
super(props);
this.state = {
columns: [
{ name: 'agent', title: 'Agent' },
{ name: 'alertGroup', title: 'Alert Group', hidden:true },
{ name: 'manager', title: 'Manager', hidden:true }
],
};
}
componentDidMount() {
this.testAlert();
}
testAlert = () => {
if (this.props.alertgroupColumn()) {
//---- get the columns from state
let columns = JSON.parse(JSON.stringify(this.state.columns))
columns[1].hidden = false
this.setState({
columns:columns
})
this.setState({
columns: [{ name: 'alertGroup', title: 'Alert Group', hidden:false }]
})
}
}

Resources