pass a variable which is inside a React function - reactjs

I have this React component
import React from "react";
import "./search.css";
// Table package
import MaterialTable from 'material-table';
function BasicSearch(props) {
return (
<div className="hovered-styled-row">
<MaterialTable
title="Students"
columns={[
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' }
]}
data={props.data}
options={{
search: true
}}
actions={[
{
icon: "add",
tooltip: 'Save User',
onClick: (event, rowData) => {
// console.log(rowData);
}
}
]}
/>
</div>
)
}
export default BasicSearch;
I am using Material Design for this component. I need to export a rowData variable which is inside
actions inside onClick.
Then the container which imports this function should be able to use this data inside a container itself. when the rowData changes the data inside a container should also change. i mean the rowData has to be
in the form of a useState function

The approach you are taking is wrong. The below are the ways to pass data from one component to another depending on your design structure.
Pass data as props and use events to communicate data changes back to parent.
If global data/or shared data use Context API.
Without full context of how the data is intend to be used and how the final jsx looks like, it's difficult to further update this answer.

Related

AGGrid React Custom Header Component - Updating state

I've taken over a React project and I'm fairly new to the library. I'm attempting to implement AG-Grid and what I think is a relatively simple custom header that renders the column name and an icon. When the icon is clicked, I need the icon to change and update the state of the custom header components parent.
My issue is that the click event works once and updates the state in the parent, but the state doesn't propagate back down to the custom header component and therefore the icon doesn't switch. Not sure if this is an AG Grid issue or a React issue.
My Custom Header Component
const WeightHeaderComponent = (params) => {
const handleClick = () => {
params.weightModeCallback()
}
return (
<span onClick={handleClick} style={{cursor: 'pointer'}}>
Weight<i className={`${params.weightModeIsPercent ? 'fa fa-percent cn-blue' : 'fa fa-tally cn-blue'}`} style={{marginLeft: '3px'}}></i>
</span>
);
};
The AG Grid column def using the custom header component:
const [columnDefs] = useState([
...
{
headerName: 'Weight',
field: 'weight',
type: 'numericColumn',
headerTooltip:
'The weight of an assignment category determines the impact an assignment will have over your overall grade.',
width: 100,
defaultMinWidth: 100,
headerComponentParams: { weightModeIsPercent: weightModeIsPercent, weightModeCallback: updateWeightMode },
headerComponent: WeightHeaderComponent
},
...
])
The relevant state hook:
const [weightModeIsPercent, setWeightModeIsPercent] = useState(true);
And finally my callback function in the parent
function updateWeightMode () {
setWeightModeIsPercent(!weightModeIsPercent);
}
After an hour of so of doc reading and head-desk beating I figured it out. I was attempting to do this in a very roundabout way when AG Grid offers a nice little api which happens to have some functions for exactly this type of thing: updating your columnDefs.
Specifically: setColumnDefs(newDefs).
My code accepts an updated parameter with which I update the columnDefs for the column I want to update.
function updateWeightMode (updatedWeightModeBool) {
const newDefs = columnDefs.map((def) => {
if (def.field === 'weight') {
return {
...def,
headerComponentParams: {
weightModeIsPercent: updatedWeightModeBool,
weightModeCallback: updateWeightMode
}
};
}
return def;
});
weightsGridRef.current.api.setColumnDefs(newDefs);
}
So, this wasn't really an issue with state (though I'm still updating the parents state for other uses).
Try using
api.refreshHeader();

AntD Tree: need help! can't pass react element as icon OR title for antd tree

I'm using the AntD tree and I have a react element that I want to pass as either an icon or a title because it has custom styling. Due to it being IP I can't share too much code, but my question is:
how can I pass a react element (see below i.e. generic name) as either a title or icon and have antD tree render it?
i.e. this is what I want to pass as a prop to the icon or title
import React from 'react';
const genericName = (props) => {
// code uses props to get some infor for Color
// cant share code due to proprietary reasons
// but it is not needed for this question
const colorHTML = getColor(Color);
return (
<div>
<div className={`colors from`}>${colorHTML}</div>
{pin}
</div>
);
};
export default genericName;
in my console you can see node.icon is a typeof react.element. I want to target that and just pass the prop into antD tree as either title or icon
i.e.
return (
<Tree
icon={node.icon}
/>
)
I've searched and similar answers were given before antD forbid the use of children and strictly allows treeData. All examples I see only use strings in titles/icons, but since antD documentation is very limited, I need to know if my use case is possible. Right now, for the life of me I can't understand why it doesn't populate.
Thank you in advance.
It should definitely work to put a JSX component as title within treeData. Take a look at this snippet, I added a Icon here in one of the titles:
import React from 'react'
import { RightCircleOutlined } from '#ant-design/icons'
type Props = {}
import { Tree } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
const treeData: DataNode[] = [
{
title: <span>{<RightCircleOutlined />} parent</span>, //icon added here
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
disabled: true,
children: [
{
title: 'leaf',
key: '0-0-0-0',
disableCheckbox: true,
},
{
title: 'leaf',
key: '0-0-0-1',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [{ title: <span style={{ color: '#1890ff' }}>sss</span>, key: '0-0-1-0' }],
},
],
},
];
const Demo: React.FC = () => {
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
console.log('selected', selectedKeys, info);
};
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
console.log('onCheck', checkedKeys, info);
};
return (
<Tree
checkable
defaultExpandedKeys={['0-0-0', '0-0-1']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
defaultCheckedKeys={['0-0-0', '0-0-1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
);
};
export default Demo;

Update state of a react component when language is changed

I have created a custom table component I forked from ant design. I reuse it in all my components, It takes an array of all columns and renders it. I pass columns as a prop called initialColumns.
My issue is whenever the user changes the language, the table contents is re rendering but not the columns which I passed, they don't get translated, How would I force a rerender when the language is changed.
custom table component
const TableComponent = (props) => {
const { initialColumns, dataSource, handleClick } = props
return ( <Table
columns={colmenu.visibleColumns}
dataSource={dataSource}
size="small"
pagination={{
pageSizeOptions: ['10', '20', '50'],
showSizeChanger: true,
}}
/>)
}
Parent component, here I call my TableComponent as pass it columns
It looks something like this:
const columns = [
{
title: t.status,
dataIndex: 'status',
key: 'status',
sorter: (a, b) => a.status.localeCompare(b.status),
...GetColumnSearchProps(['status']),
className: 'text-center',
checked: true,
},
.
.
.
.
here is how I get the translated files
const { messages: t } = useIntl()
and this is the render method:
<TableComponent
initialColumns={columns}
dataSource={data}
handleClick={addModal}
title="AABC"
/>
So how would I update the initialColumns prop when the language is changed?

How to Manipulate Dropdown placeholder, onFocus?

Am new to ReactJS. I need to make the "placeholder" which is set to "State" initially to Empty/Null when onClicked or onFocus and then when it's not focused on, it goes back to "State" again. Can someone help me with this, am very new to react so any help will be appreciated.
import React from "react";
import { render } from "react-dom";
import { Container, Button, Modal, Dropdown } from "semantic-ui-react";
const stateOptions = [
{ key: "AL", value: "AL", text: "Alabama" },
{ key: "NY", value: "NY", text: "New York" }
];
const App = () => (
<Dropdown
placeholder="State"
fluid
multiple
search
selection
options={stateOptions}
/>
);
render(<App />, document.getElementById("root"));
From React's perspective, placeholder is a state that needs to be changed according to user's actions (onClick, onBlur)
So create a state to hold placeholder value that need to change.
There are two ways (since v16.8.0 with the introduction of React Hooks).
Using Class Component
class DropDown extends React.Component {
defaultPlaceholderState = "State";
state = { placeholder: this.defaultPlaceholderState };
clearPlaceholder = () => this.setState({ placeholder: "" });
resetPlaceholder = () =>
this.setState({ placeholder: this.defaultPlaceholderState });
render() {
return (
<Dropdown
onClick={this.clearPlaceholder}
onFocus={this.clearPlaceholder}
onBlur={this.resetPlaceholder}
placeholder={this.state.placeholder}
fluid
multiple
search
selection
options={stateOptions}
/>
);
}
}
In the code above, placeholder declared as a state with default value set to this.defaultPlaceholderState.
When a user clicks on the dropdown, onClick clears the placeholder value by setting it to an empty string. Same for onFocus when the Dropdown is on focus.
When a user clicks outside (onBlur), resetPlaceHolder sets the placeholder value to the default this.defaultPlaceholderState.
Using Function Component with useState hook
React v16.8.0 introduces Hooks, which enables Function Components (not a Functional Component, as it refers to Functional Programming) to hold states.
You can use React.useState hook to hold placeholder value.
const DropDownUsingHook = () => {
const defaultPlaceholderState = "State";
const [placeholder, setPlaceholder] = React.useState(defaultPlaceholderState);
const clearPlaceholder = () => setPlaceholder("");
const resetPlaceholder = () => setPlaceholder(defaultPlaceholderState);
return (
<Dropdown
onClick={clearPlaceholder}
onFocus={clearPlaceholder}
onBlur={resetPlaceholder}
placeholder={placeholder}
fluid
multiple
search
selection
options={stateOptions}
/>
);
};
⚠ Note: Unlike the Class version, clearPlaceholder, resetPlaceholder methods and placeholder state don't use this. prefix.
The implementation is similar but you use useState hook to declare the state and the setter (setPlaceholder).
Refer to the Hooks documentation, Using State Hook for more info.
You can play around with the working code on CodeSandbox.

how to make a message without wrapping in span in react-intl

i have a problem with yahoo/react-intl thats i want to make messages in string type but when im using FormattedMessage it gives me message wrapped in span and thats not cool.
i tried formatMessage and that not working too.
i be very thankful for any help or advise this is my code:
import React from 'react';
import {FormattedMessage} from 'react-intl';
export default {
items: [
{
name: <FormattedMessage id='app.dashboard'/>,
url: '/dashboard',
icon: 'icon-speedometer',
badge: {
variant: 'info',
text: 'New',
},
},
{
title: true,
name: <FormattedMessage id='app.dashboard'/>,
// optional wrapper object
wrapper: {
// required valid HTML5 element tag
element: 'strong',
// optional valid JS object with JS API naming ex: { className: "my-class", style: { fontFamily: "Verdana" }, id: "my-id"}
attributes: {},
},
// optional class names space delimited list for title item ex: "text-center"
class: '',`enter code here`
},
for use in jsx:
it's rendered as a <span>:
<FormattedMessage id='app.dashboard'/>
it's rendered as an <option>:
<FormattedMessage id='app.dashboard' children={msg=> <option>{msg}</option>}/>
or:
<FormattedMessage id='app.dashboard' tagName="option"/>
it's rendered to nothing:
<FormattedMessage id='app.dashboard' children={msg=> <>{msg}</>}/>
or:
<FormattedMessage id="app.dashboard">{txt => txt}</FormattedMessage>
To use it in a component, you can use formatMessage() like this:
const App=()=>{
const value = intl.formatMessage({ id: 'header.nav.login' });
return(<div>{value}</>)
}
Given that you inject the intl context by yourself, Then you can use the formatMessage function.
For example, in your case:
items: [
{
name: intl.formatMessage({id:'app.dashboard'});
}
]
To get intl in your component you have two choices:
get it from your component's context
use injectIntl to get it in your props.
If you're not in a component, it gets slightly harder but I would just put the id instead of the formatted message in name and then use the react-intl context when available. Here, in the component that consumes and displays this list of items.
The solution here is to upgrade react-intl to version 3.
In version 3, the <FormattedMesage> (and similarly others react-intl components) is rendering into React.Fragment.
If you want to render it to something else you can specify textComponent prop on IntlProvider, eg.:
<IntlProvider textComponent="span" />
See info in Migration Guide (v2 -> v3).

Resources