Simple React issue - javascript

Having trouble with a little snippet of js, I keep getting the error:
Failed to compile
./src/App.js
Line 81:9: Expected an assignment or function call and instead saw an expression no-unused-expressions
Search for the keywords to learn more about each error.
This error occurred during the build time and cannot be dismissed.
Code is as follows:
function TaskList() {
const deadlines = [
{ title: "wash the dishes!"},
{ title: "take out the trash!" },
{ title: "walk the dog!"},
];
return (
<div style={{ padding: "30px" }}>
{deadlines.map((task) => {
<>
<a>{task.title}</a>
</>
})}
</div>
);
}

You just need to return your JSX snippet in the map callback:
function TaskList() {
const deadlines = [
{ title: "wash the dishes!"},
{ title: "take out the trash!" },
{ title: "walk the dog!"},
];
return (
<div style={{ padding: "30px" }}>
{deadlines.map((task) => {
return (
<>
<a>{task.title}</a>
</>
);
})}
</div>
);
}

You need to return the jsx from inside the map method.
function TaskList() {
const deadlines = [
{ title: "wash the dishes!"},
{ title: "take out the trash!" },
{ title: "walk the dog!"},
];
return (
<div style={{ padding: "30px" }}>
{deadlines.map((task) => {
return ( // return the jsx
<>
<a>{task.title}</a>
</>
);
})}
</div>
);
}

Related

React loop through nested object

I'm fetching data from strapi.
The response for my navigation object looks like that (simplified):
[
{
"id":1,
"title":"Home",
"order":1,
"items":[
{
"id":2,
"title":"3D Assets",
"order":1,
"items":[
]
},
{
"id":4,
"title":"3D Plants",
"order":2,
"items":[
]
},
{
"id":3,
"title":"Surfaces",
"order":3,
"items":[
{
"id":5,
"title":"Asphalt",
"order":1,
"items":[
]
}
]
}
]
},
{
"id":6,
"title":"Collections",
"order":2,
"items":[
],
"icon":""
}
]
Actually I'm looping through my navigation like that:
{Object.entries(navigationItems).map(([key, value]) => {
return(
<div className="nav_item">
<div className="nav_item_parent">{value.title}
{Object.entries(value.items).map(([key, value]) => {
return(
<div className="nav_item_child">{value.title}
{Object.entries(value.items).map(([key, value]) => {
return(
<div className="nav_item_child">{value.title}</div>
)
})}
</div>
)
})}
</div>
</div>
)
})}
How can I create a navigation without repeating the code for each child? (Because the object could be nested many times)
Here just placing some demo code , please have reference and implement as per your need
Parent Component
import React, {Children} from 'react';
function recursionExample(props) {
let data = [
{
id: 1,
title: 'Home',
order: 1,
items: [
{
id: 2,
title: '3D Assets',
order: 1,
items: [],
},
{
id: 4,
title: '3D Plants',
order: 2,
items: [],
},
{
id: 3,
title: 'Surfaces',
order: 3,
items: [
{
id: 5,
title: 'Asphalt',
order: 1,
items: [],
},
],
},
],
},
{
id: 6,
title: 'Collections',
order: 2,
items: [],
icon: '',
},
];
return (
<div>
{data.map((item, index) => {
return (
<>
<div>{item.title}</div>
{item.items && <ChildrenCom data={item.items}></ChildrenCom>}
</>
);
})}
</div>
);
}
export default recursionExample;
Now below component will call till last-child , as it is called recursively
import React from 'react';
function ChildrenCom(props) {
let {data} = props;
return (
<div>
{data.map((item, index) => {
return (
<>
<div>{item.title}</div>
{item.items && <ChildrenCom data={item.items}></ChildrenCom>}
</>
);
})}
</div>
);
}
export default ChildrenCom;
We could use Depth First Traversal to help us avoid duplication. If you're not comfortable with Depth First Traversal or Recursion, I would recommend you to go through the following snippet initially.
function dfs(item, depth = 0) {
if (!item || Object.keys(item).length === 0) return;
console.log("\t".repeat(depth), item.title);
for (const subItem of item.items) {
dfs(subItem, depth + 1);
}
}
// Consider payload to be the response that you get from the API.
for (const item of payload) {
dfs(item)
}
Once you're comfortable, you could translate it into React.
const Nav = ({ item, depth = 0 }) => {
if (!item || Object.keys(item).length === 0) return;
return (
<>
<p style={{ paddingLeft: `${depth * 64}px` }}>{item.title}</p>
{item.items.map((subItem, index) => (
<Nav item={subItem} depth={depth + 1} />
))}
</>
);
};
export default function App() {
return (
<div className="App">
{payload.map((item) => (
<Nav item={item} />
))}
</div>
);
}
Just a simple recursive tree walk. A component like this:
const NodePropTypes = PropTypes.objectWithShape({
id: PropTypes.number,
title: PropTypes.string,
items: PropTypes.array,
});
const NavListPropTypes = {
nodes: PropTypes.arrayOf( NodePropTypes ),
};
function NavList( props ) {
const nodes = props?.nodes ?? [];
if (nav.length) {
return (
<list>
<ListItems nodes={nodes} />
</list>
);
}
}
NavList.propTypes = NavListPropTypes
function ListItems( props ) {
const nodes = props?.nodes ?? [];
return (
<>
{ nodes.map( node => <ListItem node={node} /> ) }
</>
);
}
ListItems.propTypes = NavListPropTypes;
function ListItem( props ) {
const node = props?.node ?? {};
return (
<li id={node.id} >
<p> {node.title} </p>
<NavList nodes={node.items} />
</li>
);
}
ListItem.propTypes = NodePropTypes;
which can be rendered passing your navigation response:
<NavList nodes={navigationResponse} />
And should yield something like this:
<list>
<li id="1" >
<p> Home </p>
<list>
<li id="2" >
<p> 3D Assets </p>
</li>
<li id="4" >
<p> 3d Plants </p>
</li>
<li id="3" >
<p> Surfaces </p>
<list>
<li id="5" >
<p> Asphalt </p>
</li>
</list>
</li>
</list>
</li>
<li id="6" >
<p> Collections </p>
</li>
</list>

Column of table from different API (React)

I have to fill the table with data which I have returned from different API : the first from smart contract and the second one from a MySQL table using axios.
Both of the sets of data returned are arrays and each elements with the same id I want to put it into a row.
I succeeded to put the data only from the smart contract.
Here's the code of my component :
function CandidaturesList() {
const [account, setAccounts] = useState(null);
const [contract, setContract] = useState(null);
const [candidatures, setCandidatures] = useState(null);
const [stateCandidatures, setStateCandidatures] = useState(null);
useEffect(() => {
async function fetchData() {
const web3 = await getWeb3();
const accounts = await web3.eth.getAccounts();
const networkId = await web3.eth.net.getId();
const deployedNetwork = OffreEmploiContract.networks[networkId];
const instance = new web3.eth.Contract(
OffreEmploiContract.abi,
deployedNetwork && deployedNetwork.address,
);
setAccounts(accounts);
setContract(instance);
const response = await instance.methods.getApply().call({ from: accounts[0] });
console.log(response);
setCandidatures(response);
axios.get('http://localhost:4000/api/getAll').then((res) => {
setStateCandidatures(res.data);
})
}
fetchData();
});
const project = [
{
title: "COMPANIES",
dataIndex: "nomCompagnie",
align: 'center',
render: text => (
<div className="avatar-info">
<Title level={5}>{text}</Title>
</div>
)
},
{
title: "JOB TITLE",
dataIndex: "titre_poste",
align: 'center',
render: text => (
<>
<div className="semibold">{text}</div>
</>)
},
{
title: "STATUS",
width: "15%",
dataIndex: "status",
align: 'center',
render: text => (
<>
<br>{text}</br>
<br></br>
<Steps current={1} progressDot={(dot, { status, index }) => (
<Popover
content={
<span>
step {index} status: {status}
</span>
}
>
{dot}
</Popover>
)} >
<Step title="Published" />
<Step title="Job interview" description="Mon, 18 Apr 2022" />
<Step title="Waiting for decision" />
<Step title="Completed" />
</Steps>,
</>)
},
{
title: "FINAL DECISION",
dataIndex: "decision",
align: 'center',
render: text => (
<>
{
text === "Valide" || text === "Refused" ?
<Tag color="cyan">{text}</Tag>
:
<Tag icon={<SyncOutlined spin />} color="processing">{text}</Tag>
}
</>
)
},
];
return (
<>
<Card
bordered={false}
className="criclebox tablespace mb-24"
title="Your Candidature"
extra={
<>
</>
}
>
<div className="table-responsive">
<Table
columns={project}
dataSource={candidatures }
pagination={false}
className="ant-border-space"
/>
</div>
</Card>
</>
);
}
export default CandidaturesList;
I must fill the Steps with the state stateCandidatures which is an array of objects , example :
{id: 1, date_entretien: 'Mon Apr 25 2022', status: 'waiting for interview'},
{id: 2, date_entretien: null, status: 'Published'}
and this is an example of the state candidatures :
[ id: '1', nomCompagnie:'Company1', titre_poste: 'manager', decision:'valide', …]
[ id: '2', nomCompagnie:'Company2', titre_poste: 'developer', decision:'processing', …]
and the second problem is i don't know how to fill the steps with those data ( the code shows a static steps)

How to add and edit list items in a dual list in reactjs?

I am pretty new to React js and trying different ways to make a to-do list to understand it further. I have a parent component that renders two child components. I figured out how to transfer the items between the two lists. How do I add items to the 2 lists separately from the UI? I am not able to figure that out. I need two input textboxes for each list and also should be able to edit the list items. Can anybody please help me?
import React,{useState,useEffect} from 'react'
import { Completed } from './Completed'
import { Pending } from './Pending'
export const Items = () => {
const [items,setItems]=useState([
{
id: 1,
title:'Workout',
status:'Pending'
},
{
id: 2,
title:'Read Books',
status:'Pending'
},
{
id: 3,
title:'Cook Pizza',
status:'Pending'
},
{
id: 4,
title:'Pay Bills',
status:'Completed'
},
{
id: 5,
title:' Watch Big Short',
status:'Completed'
},
{
id: 6,
title:' Make nutrition Plan',
status:'Pending'
}
])
const updateStatus=(id,newStatus)=>{
let allItems=items;
allItems=allItems.map(item=>{
if(item.id===id){
console.log('in here')
item.status=newStatus;
}
return item
})
setItems(allItems)
}
return (
<div class="items">
<Pending items={items} setItems={setItems} updateStatus={updateStatus}/>
<Completed items={items} setItems={setItems} updateStatus={updateStatus}/>
</div>
)
}
import React from 'react'
export const Completed = ({items,setItems,updateStatus}) => {
return (
<div className="completed">
<h1>RIGHT</h1>
{
items && items.map(item=>{
if(item && item.status==='Completed')
return <><p className="item" key={item.id}>{item.title} <button className="mark_pending" key={item.id} onClick={()=>{updateStatus(item.id,'Pending')}}> Move Left</button></p></>
})
}
</div>
)
}
import React from 'react'
export const Pending = ({items,setItems,updateStatus}) => {
return (
<div className="pending">
<h1>LEFT</h1>
{
items && items.map(item=>{
if(item && item.status==='Pending')
return <><p className="item" key={item.id}>{item.title} <button className="mark_complete" key={item.id} onClick={()=>{updateStatus(item.id,'Completed')}}>Move Right</button></p></>
})
}
</div>
)
}
What do you mean by "separately from the UI" ?
import React, { useState } from "react";
const initialStatus = "Pending";
const initialData = [
{
id: 1,
title: "Workout",
status: "Pending",
},
{
id: 2,
title: "Read Books",
status: "Pending",
},
{
id: 3,
title: "Cook Pizza",
status: "Pending",
},
{
id: 4,
title: "Pay Bills",
status: "Completed",
},
{
id: 5,
title: " Watch Big Short",
status: "Completed",
},
{
id: 6,
title: " Make nutrition Plan",
status: "Pending",
},
];
const Box = ({ id, title, status, setItems, items }) => {
return (
<button
onClick={() => {
const newItems = [...items];
const index = items.findIndex((v) => v.id == id);
newItems[index].status =
newItems[index].status == initialStatus ? "Completed" : initialStatus;
setItems(newItems);
}}
>
{title}
</button>
);
};
export const Items = () => {
const [items, setItems] = useState(initialData);
return (
<div style={{ display: "flex" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>LEFT</h1>
{items
.filter((v) => v.status === initialStatus)
.map((props) => (
<Box {...props} key={props.id} setItems={setItems} items={items} />
))}
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>Right</h1>
{items
.filter((v) => v.status !== initialStatus)
.map((props) => (
<Box {...props} key={props.id} setItems={setItems} items={items} />
))}
</div>
</div>
);
};
export default Items;

Add custom add-button in material-table

Currently I have a simple material-table like this:
<MaterialTable
options={myOptions}
title="MyTitle"
columns={state.columns}
data={state.data}
tableRef={tableRef} // Not working
editable={{
onRowAdd: ...,
onRowDelete: ...,
onRowUpdate: ...
}}
/>;
where I'm trying to a create new add button (not edit the current one): each Row in the Bar Column should have a custom add button. I've looked through the MaterialTable source code but I couldn't reproduce the code that is used for the default add button which is:
calculatedProps.actions.push({
icon: calculatedProps.icons.Add,
tooltip: localization.addTooltip,
position: "toolbar",
disabled: !!this.dataManager.lastEditingRow,
onClick: () => {
this.dataManager.changeRowEditing();
this.setState({
...this.dataManager.getRenderState(),
showAddRow: !this.state.showAddRow,
});
},
});
in particular I can't get to access the dataManager variable.
That is how the current table looks like, and I need to add the add button where there is the red sign.
I think this is what you are looking for:
The Actions column represents the default actions set. I added an specific button using custom column rendering (docs):
//..previous columns definition
{
title: "Custom Add",
field: "internal_action",
editable: false,
render: (rowData) =>
rowData && (
<IconButton
color="secondary"
onClick={() => addActionRef.current.click()}
>
<AddIcon />
</IconButton>
)
}
*Using rowData as conditional, prevents from rendering while filling the addition row.
Then I triggered the add action as shown here:
const MyComponent() {
const addActionRef = React.useRef();
return (
<>
<button onClick={() => addActionRef.current.click()}>
Add new item
</button>
<MaterialTable
//...
components={{
Action: props => {
//If isn't the add action
if (typeof props.action === typeof Function || props.action.tooltip !== 'Add') {
return <MTableAction {...props} />
} else {
return <div ref={addActionRef} onClick={props.action.onClick}/>;
}}
}}
editable={{
onRowAdd: (newData, oldData) => Promise.resolve(); //your callback here
}}
/>
</>
);
}
I extended the original snippet in order to complete the addition cycle. If you need to handle different types of actions, I think Editable section from the oficial docs would be handy.
Hope this works for you! Full code and sandbox here:
import React, { Fragment, useState } from "react";
import MaterialTable, { MTableAction } from "material-table";
import AddIcon from "#material-ui/icons/AddAlarm";
import IconButton from "#material-ui/core/IconButton";
export default function CustomEditComponent(props) {
const tableRef = React.createRef();
const addActionRef = React.useRef();
const tableColumns = [
{ title: "Client", field: "client" },
{ title: "Name", field: "name" },
{ title: "Year", field: "year" },
{
title: "Custom Add",
field: "internal_action",
editable: false,
render: (rowData) =>
rowData && (
<IconButton
color="secondary"
onClick={() => addActionRef.current.click()}
>
<AddIcon />
</IconButton>
)
}
];
const [tableData, setTableData] = useState([
{
client: "client1",
name: "Mary",
year: "2019"
},
{
client: "client2",
name: "Yang",
year: "2018"
},
{
client: "client3",
name: "Kal",
year: "2019"
}
]);
return (
<Fragment>
<MaterialTable
tableRef={tableRef}
columns={tableColumns}
data={tableData}
title="Custom Add Mode"
options={{
search: false
}}
components={{
Action: (props) => {
//If isn't the add action
if (
typeof props.action === typeof Function ||
props.action.tooltip !== "Add"
) {
return <MTableAction {...props} />;
} else {
return <div ref={addActionRef} onClick={props.action.onClick} />;
}
}
}}
actions={[
{
icon: "save",
tooltip: "Save User",
onClick: (event, rowData) => alert("You saved " + rowData.name)
}
]}
editable={{
onRowAdd: (newData) =>
Promise.resolve(setTableData([...tableData, newData]))
}}
/>
</Fragment>
);

Using Apollo GraphQL refetch method from outside

My render function
translateFileAndRefetchQuery = (urn) => {
translateFile(urn);
// How do I refetch data from here?
};
render() {
const translateFormatter = (cell, row) => {
return (
<span>
<Button
onClick={() => translateFileAndRefetchQuery(row.urn)}
>
Translate
</Button>
</span>
);
};
const columns = [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'lastUpdated',
text: 'Last updated',
},
{
dataField: 'lastTranslated',
text: 'Translate',
formatter: translateFormatter,
},
];
return (
<>
<h3>Models</h3>
<h4>Root > Plans</h4>
{this.state.plansFolderUrn != null &&
<Query query={getProjects()}>
{(data, refetch) => (
<>
<BootstrapTable
keyField="name"
data={data.projects}
columns={columns}
/>
</>
)}
</Query>
}
</>
);
}
I'm using the apollo data fetcher which have a refetch method. I need to call this from outside the Query.
How do i do this?
You could pass the function around in different callbacks. I added a decorator to translateFormatter to not call it right away :
translateFileAndRefetchQuery = (urn, refetch) => {
translateFile(urn);
refetch();
};
render() {
const translateFormatter = refetch => (cell, row) => {
return (
<span>
<Button
onClick={() => translateFileAndRefetchQuery(row.urn, refetch)}
>
Translate
</Button>
</span>
);
};
const getColumns = refetch => [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'lastUpdated',
text: 'Last updated',
},
{
dataField: 'lastTranslated',
text: 'Translate',
formatter: translateFormatter(refetch),
},
];
return (
<>
<h3>Models</h3>
<h4>Root > Plans</h4>
{this.state.plansFolderUrn != null &&
<Query query={getProjects()}>
{(data, refetch) => (
<>
<BootstrapTable
keyField="name"
data={data.projects}
columns={getColumns(refetch)}
/>
</>
)}
</Query>
}
</>
);
}

Categories

Resources