How can i see my array on my component ? / React / Javascript - javascript

I have a element like :
const DropdownElements = [
{
key: 1,
title: "Şehir",
placeholder: "Şehir Seçiniz",
apiUrl: "https://api.npoint.io/995de746afde6410e3bd",
type: "city",
selecteditem: "",
data : [],
},
{
key: 2,
title: "İlçe",
placeholder: "İlçe Seçiniz",
apiUrl: "https://api.npoint.io/fc801dbd3fc23c2c1679", // its my apis. They hold datas from json
type: "district",
selecteditem: "",
data : [],
},
]
I fetching that url in App in useEffect.
const App = () => {
useEffect(() => {
DropdownElements.map((x) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((vb) => {
x.data=vb // If i write x.data.push(vb) i can see it on my component but its not giving pure array.
console.log(x.data) // I can see my datas perfectly. I trying fill my data.
});
});
}, []);
And i setting it like that :
<Space>
{DropdownElements.map((x) => {
return (
<PickerCompanent
showSearch
selecteditem={idhold}
key={x.key}
placeholder={x.placeholder}
type={x.type}
datasource={x.data} // I gave my datasource x.data that i filled .
onFocus={onFocus}
onChange={z=>onChange(z)}
onFocus={onFocus}
onSearch={onSearch}
></PickerCompanent>
);
})}
</Space>
But in my component when i try write like console.log(props) my datasource is empty array. How can i see my datas on my component ? I need set my array to a state in my component.

It seems like you aren't using any kind of state in your code.
const App = () => {
const [myData, setMyData] = useState();
useEffect(() => {
DropdownElements.map((x) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((vb) => {
x.data=vb // If i write x.data.push(vb) i can see it on my component but its not giving pure array.
console.log(x.data) // I can see my datas perfectly. I trying fill my data.
// in here you'll want to be adding your data to some state
// e.g.
setMyData(x.data);
});
});
}, []);
Then within your component, use that state:
datasource={myData}

Your object is updating but not view. To achieve this you need have a component state, to which we can update and trigger return again to update view.
const App = () => {
const [myData, setMyData] = useState(DropdownElements);
useEffect(() => {
myData.map((x, i) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((result) => {
myData[i].data = result;
setMyData(myData);
});
});
}, []);
return (
<Space>
{myData.map((x) => {
return (
<PickerCompanent
showSearch
selecteditem={idhold}
key={x.key}
placeholder={x.placeholder}
type={x.type}
datasource={x.data} // I gave my datasource x.data that i filled .
onFocus={onFocus}
onChange={z=>onChange(z)}
onFocus={onFocus}
onSearch={onSearch}
></PickerCompanent>
);
})}
</Space>
);

Related

Request to api works fine in component but not when using provider with react

When making a request to my API from a component and using react-data-table-component everything works perfectly but if I try to make the request from my Product Provider the pagination is incorrect and no longer works as expected.
With this code I make the request, datatable and pagination from my component working perfectly:
import React, { useState, useEffect, useCallback, useMemo } from "react";
import axiosClient from "../config/axiosClient";
import DataTable from 'react-data-table-component-with-filter'
import { CSVLink } from "react-csv"
import { Link } from 'react-router-dom'
import useProducts from "../hooks/useProducts";
const removeItem = (array, item) => {
const newArray = array.slice();
newArray.splice(newArray.findIndex(a => a === item), 1);
return newArray;
};
const ProductsTest = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [totalRows, setTotalRows] = useState(0);
const [perPage, setPerPage] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [searchBox, setSearchBox] = useState('')
const STRING_TRADUCTIONS = { "KILOGRAM" : "KILOGRAMOS", "GRAMS" : "GRAMOS", "BOX" : "CAJA", "PACKAGE" : "PAQUETE", "BOTTLE" : "BOTE", "PIECES" : "PIEZAS", "BAG" : "BOLSA", "LITER" : "LITRO" }
const fetchUsers = async (page, limit = perPage, search = searchBox) => {
setLoading(true)
const dataOnLs = localStorage.getItem('cmtjs')
const config = {
headers: {
"Content-Type": "application/json",
apiKey: dataOnLs
} ,
params: {
limit,
page,
search
}
}
const response = await axiosClient(`/products`, config)
const data = response.data.products.docs.map( doc => (
{
_id: doc._id,
idProduct: doc.idProduct,
barCode: doc.barCode,
name: doc.name,
presentation: STRING_TRADUCTIONS[doc.presentation],
salePrice: doc.salePrice,
purchasePrice: doc.purchasePrice,
stock: doc.stock,
user: doc.user.username,
category: doc.category.name,
provider: doc.provider.name
}
))
setData(data);
setTotalRows(response.data.products.totalDocs);
setLoading(false);
};
useEffect(() => {
fetchUsers(1)
}, []);
const columns = useMemo(
() => [
{
name: "ID",
selector: "idProduct",
sortable: true
},
{
name: "Código de Barras",
selector: "barCode",
sortable: true
},
{
name: "Nombre",
selector: "name",
sortable: true
},
{
name: "Presentación",
selector: "presentation",
sortable: true
},
{
name: "Precio",
selector: "salePrice",
sortable: true
},
{
name: "Stock",
selector: "stock",
sortable: true
},
{ cell: row =>
<Link to={ `/dashboard/product/${row._id}`}>
<button className='btn btn-ghost text-xs'>
Mas
</button>
</Link>}
]
);
const handlePageChange = page => {
fetchUsers(page);
setCurrentPage(page);
};
const handlePerRowsChange = async (newPerPage, page) => {
fetchUsers(page, newPerPage);
setPerPage(newPerPage);
}
const headers = [
{ label: "ID", key: "idProduct" },
{ label: "Código de Barras", key: "barCode" },
{ label: "Nombre", key: "name" },
{ label: "Presentación", key: "presentation" },
{ label: "Precio Venta", key: "salePrice" },
{ label: "Precio Compra", key: "purchasePrice" },
{ label: "Stock", key: "stock" },
{ label: "Creador", key: "user" },
{ label: "Categoría", key: "category" },
{ label: "Proveedor", key: "provider" }
]
const paginationComponentOptions = {
rowsPerPageText: 'Mostrar',
rangeSeparatorText: 'de',
selectAllRowsItem: true,
selectAllRowsItemText: 'Todos',
};
const clear = () => {
setPerPage(10)
setSearchBox('')
fetchUsers(1, 10, '')
}
return (
<div>
<input type="text" onChange={(e)=> setSearchBox(e.target.value)}/>
<button onClick={ ()=> fetchUsers()}>Buscar</button>
<CSVLink data={data} headers={headers} filename={"productos.cdtmx.csv"} className="cursor-pointer">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABmJLR0QA/wD/AP+gvaeTAAACnUlEQVRoge2YXUhUQRiGn7HVRVddc8k0QawQw6hQohKSlsp+oDulQBGCbuxGQ1itDIx+IIWINKK86S4o6ibFEG9ywQzCEJLVSCylorYf1CJaXXe6SPvZ1ePZs3tczfNcfsP3zfvOzHc4M2BgYGAQSYTWxJSrReUg6oHEYHNtuRu1TDkupKx27Tp38+9glJZKv9AmPgQSpYiq9w+GYGBBxU8jrf6RUAwsCgwDkcYwEGlM/gFLVf4JkBcEWJQSvw+/Ua4cJYixWjElxoemcB4CDKgRrwqfZGJ0lImpqYChFe53IZefIeAIhUX8DDJsleZkyffA8jBgNkXTe+ouXy93U2Ev+R3PSE7jU70T96VHZNrSdROphCoDHu8kZ1quAVC1u4x4cxwAdQfLMZuiaei4xevPb/VTqYDqI9Ta56Rj4Ak2SxLHCw6zaU0Wxbl7Gfw4QlPnbT01KjLLZ3RuTj9oxJ61lQp7CYUbdiAQVN5rwOOd1EvfvATVxAMfXtHcdZ+k2ATy127hzrN2nIM9emlTRVA7AJAwff4BhJj/QmfpDuwNT0pCsNPOSVA7ULA+j7Jth3g63EfXUC9H8vazJ3t72MRoQbUBsymaK0UOhBCcbbtBbUsTUkoai2uIi4nVU6Miqg2c3HeM7NWZtPc/xjnYQ8+Ii9Y+JxnJadQUHtVToyKqDOSkrqPSXopP+jj/8M+jQF3bdby+KSrspWxOz9JNpBKqmtj1fojk6oKA+Ev3CCsdO8MuKhiWx7/QYmY2A9/CVt2n/4Vgth6oBS4Cod0FfVKa3Z4fgMd/yPb8i+ay/pma30ZTD+RoXl5rxiqtqbxo7vxH83/ZA0sKw0CkWdYGxsOmQj1j/gHNBoQQDhABBXVkTEocCzifgYGBgQp+AlpMnf09Cu/RAAAAAElFTkSuQmCC"/>
</CSVLink>
<DataTable
columns={columns}
data={data}
progressPending={loading}
pagination
paginationServer
paginationTotalRows={totalRows}
paginationDefaultPage={currentPage}
onChangeRowsPerPage={handlePerRowsChange}
onChangePage={handlePageChange}
selectableRows
//onSelectedRowsChange={({ selectedRows }) => console.log(selectedRows)}
paginationComponentOptions={paginationComponentOptions}
noDataComponent="No hay resultados"
/>
{
searchBox && searchBox !== '' && <button onClick={ () => clear() }>Limpiar</button>
}
</div>
)
}
But I have my product provider where I make a get request to all my products, avoiding making the requests from my component and having the data globally, but if I use "getProducts" from my provider, the first view of the datatable is correct however , when clicking on a page or next, the pager advances but the data displayed does not, for example: it shows me the first 10 records but I ask for the next 10 and the pager advances correctly but the data is still the first 10 records, No I know how to use my provider and make the pager show the following data depending on what the user needs.
This is the code of my provider to obtain the product data
const getProducts = async(page, limit, search) => {
const dataOnLs = localStorage.getItem('cmtjs')
const config = {
headers: {
"Content-Type": "application/json",
apiKey: dataOnLs
} ,
params: {
page,
limit,
search
}
}
try {
const { data } = await axiosClient(`/products`, config)
setProducts(data)
} catch (error) {
So in my component I call "getProducts" from my provider to have the products data in "products" using the useEffect hook
useEffect(() => {
getProducts()
setData(products.products?.docs)
setTotalRows(products.products?.totalDocs)
setLoading(false)
}, []);
In my paginator to obtain the following 10 product records, I click and the text changes that indicates which page is being shown, but the data remains the same as the first page
const handlePageChange = page => {
getProducts(page); // it does not show the next 10 records as it happened in the fetch of my component
setCurrentPage(page); // OK
};
In the same way, my browser no longer works using it in this way, I only changed the function to call my provider now, but it does not work
<input type="text" onChange={(e)=> setSearchBox(e.target.value)}/>
<button onClick={ ()=> getProducts()}>Buscar</button>
I would like to know if you can help me to make my datatable and browser work using my provider. Thanks.
In this code
useEffect(() => {
getProducts()
setData(products.products?.docs)
setTotalRows(products.products?.totalDocs)
setLoading(false)
}, []);
You are calling getProducts(), which is asynchronous. Then you try setData(products...), but the asynchronous call did not finish yet, so products was not updated yet. When eventually the asynchronous code terminates, the useEffect statement is not triggered again, because the dependency array states that the effect is only executed when the component mounts.
Split up your effect in two parts instead, so the second effect gets triggered when new products are available:
useEffect(() => {
getProducts()
}, []);
useEffect(() => {
setData(products.products?.docs)
setTotalRows(products.products?.totalDocs)
setLoading(false)
}, [products]);

React How can i make new array when i choose some item from picker?

I thinking for few days but cant realize how can i make it. I have 4 json data and 4 picker.
Its for city,district,village,neirborhood. In first i must choose city then in second picker it must show district about that i choose city. When i choose district from picker third one must show villages about that district. And neirborhood is same too. In that json datas they have some connection. Like city json have ' id-name' district have 'id-cityid-name' village have 'id-districtid-name' neirborhood have 'id-villageid-name' Like that. But i cant figure out how can i make it. Its my codes I really stuck with that hardly i need some help please. Thank you! My codes :
Elements :
const DropdownElements = [
{
key: 1,
title: "Şehir",
placeholder: "Şehir Seçiniz",
apiUrl: "https://api.npoint.io/995de746afde6410e3bd",
type: "city",
selecteditem: "",
data : [],
},
{
key: 2,
title: "İlçe",
placeholder: "İlçe Seçiniz",
apiUrl: "https://api.npoint.io/fc801dbd3fc23c2c1679",
type: "district",
selecteditem: "",
data : [],
},
{
key: 3,
title: "Köy",
placeholder: "Köy Seçiniz",
apiUrl: "https://api.npoint.io/72cf025083b70615b8bb",
type: "village",
selecteditem: "",
data : [],
},
{
key: 4,
title: 'Mahalle',
placeholder:'Mahalle Seçiniz',
apiUrl: 'https://api.npoint.io/0c04c63923c8ca4e117b',
type: 'neighborhood',
selecteditem: "",
data : [],
},
];
Component :
const PickerCompanent = (props) => {
const [xdata, setData] = useState([]);
const [newData, setNewData] = useState([]);
let x;
let y = [];
// data.filter((a) => a.il_id == "3");
useEffect(() => {
props.datasource.then(setData);
switch (props.type) {
case "city":
x = props.selecteditem;
setNewData(xdata);
break;
case "district":
y = xdata.filter((element) => {
if (props.selecteditem === element.id) {
return element;
}
});
break;
case "village":
console.log("village");
break;
default:
console.log("def");
break;
}
}, [props.datasource]);
return (
<Select
showSearch
style={{ width: 200, marginLeft: 15 }}
placeholder={props.placeholder}
optionFilterProp="children"
onChange={(x) => props.onChange(x)}
onFocus={props.onFocus()}
datasource={xdata}
onSearch={props.onSearch()}
filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{xdata &&
xdata.map((x) => {
return (
<Select.Option key={x.id} value={x.id}>
{x.name}{" "}
</Select.Option>
);
})}
</Select>
);
};
My App :
const App = () => {
const [dataap, setDataAp] = useState([]);
const [idhold, setIDHold] = useState();
const filldata = (value) => {};
function onChange(value) {
setIDHold(value);
console.log(value);
}
const getData = (value, type) => {
return fetch(value)
.then((x) => x.json())
.then((y) => {
return y;
});
};
function onFocus() {}
function onSearch(val) {}
return (
<Space>
{DropdownElements.map((x) => {
return (
<PickerCompanent
showSearch
selecteditem={idhold}
key={x.key}
placeholder={x.placeholder}
type={x.type}
datasource={getData(x.apiUrl)}
onFocus={onFocus}
onChange={(z) => onChange(z)}
onFocus={onFocus}
onSearch={onSearch}
></PickerCompanent>
);
})}
</Space>
);
};
If you need i can give my teamviewer or skype too. I really need that help thanks for replies!
Sandbox : codesandbox.io/s/runtime-monad-vxit
https://codesandbox.io/s/mystifying-moore-7w105?file=/src/App.js
Select CityTwo to see the dropdown update.
You need a switch. Updating arrays inside state is tricky. You can't populate or push anything in an array that's in state. Update your array outside state, THEN update state.

how to using a custom function to generate suggestions in fluent ui tag picker

I am trying to use the tagPicker from fluent ui. I am using as starting point the sample from the site:
https://developer.microsoft.com/en-us/fluentui#/controls/web/pickers
The problem is that the object I have has 3 props. the objects in the array are {Code:'string', Title:'string', Category:'string'}. I am using a state with a useeffect to get the data. SO far works fine, the problem is that the suggestion are rendered blank. It filter the items but does not show the prop I want.
Here is my code:
import * as React from 'react';
import {
TagPicker,
IBasePicker,
ITag,
IInputProps,
IBasePickerSuggestionsProps,
} from 'office-ui-fabric-react/lib/Pickers';
import { mergeStyles } from 'office-ui-fabric-react/lib/Styling';
const inputProps: IInputProps = {
onBlur: (ev: React.FocusEvent<HTMLInputElement>) => console.log('onBlur called'),
onFocus: (ev: React.FocusEvent<HTMLInputElement>) => console.log('onFocus called'),
'aria-label': 'Tag picker',
};
const pickerSuggestionsProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested tags',
noResultsFoundText: 'No color tags found',
};
const url="url_data"
export const TestPicker: React.FunctionComponent = () => {
const getTextFromItem = (item) => item.Code;
const [state, setStateObj] = React.useState({items:[],isLoading:true})
// All pickers extend from BasePicker specifying the item type.
React.useEffect(()=>{
if (!state.isLoading) {
return
} else {
caches.open('cache')
.then(async cache=> {
return cache.match(url);
})
.then(async data=>{
return await data.text()
})
.then(data=>{
const state = JSON.parse(data).data
setStateObj({items:state,isLoading:false})
})
}
},[state.isLoading])
const filterSuggestedTags = (filterText: string, tagList: ITag[]): ITag[] => {
return filterText
? state.items.filter(
tag => tag.Code.toLowerCase().indexOf(filterText.toLowerCase()) === 0 && !listContainsTagList(tag, tagList),
).slice(0,11) : [];
};
const listContainsTagList = (tag, state?) => {
if (!state.items || !state.items.length || state.items.length === 0) {
return false;
}
return state.items.some(compareTag => compareTag.key === tag.key);
};
return (
<div>
Filter items in suggestions: This picker will filter added items from the search suggestions.
<TagPicker
removeButtonAriaLabel="Remove"
onResolveSuggestions={filterSuggestedTags}
getTextFromItem={getTextFromItem}
pickerSuggestionsProps={pickerSuggestionsProps}
itemLimit={1}
inputProps={inputProps}
/>
</div>
);
};
I just got it, I need to map the items to follow the {key, name} from the sample. Now it works.
setStateObj({items:state.map(item => ({ key: item, name: item.Code })),isLoading:false})

Redux helper function to check if a value is in the store

I have a filter panel where the user can select different color filters:
// ColorButton.jsx
function ColorButton({ color }) {
const handleFilterSelected = ({ id }) => {
dispatch(applyFilter({ type: "colors", value: id }));
};
return (
<div className="color-button" onClick={() => handleFilterSelected(color)}>
{isFilterSelected({ type: "colors", value: color.id }) ? "yay" : "nay"}
</div>
);
}
The selected filters are stored in the redux store and the isFilterSelect function looks like this:
// redux/utils/filter.utils.js
export const isFilterSelected = ({ type, value }) => {
const {
filters: { applied }
} = store.getState();
return applied
.filter((f) => f.type === type)
.map((f) => f.value)
.includes(value);
};
The issue is that the check runs before a selected filter is added to the applied array.
As a more general question - is it even a good idea to have "helper" functions that depend on the redux store?
Your helper function there should be written as a selector that gets the current state, and you should be using useSelector instead of store.getState manually, as that will update your component when the selector value changes.
function ColorButton({ color }) {
const isSelected = useSelector(state => isFilterSelected(state, { type: "colors", value: color.id }));
return (
<div className="color-button">
{isSelected ? "yay" : "nay"}
</div>
);
}
// redux/utils/filter.utils.js
export const isFilterSelected = (state, { type, value }) => {
return state.filters.applied
.filter((f) => f.type === type)
.map((f) => f.value)
.includes(value);
};

Ant Design Table component not displaying state-based dataSource change

I am using Ant Design for my React project and I'm having trouble with the Table component. I have a list of tasks to which I add a new task based on a Form content - currently just by adding to an array of objects (taskListMock in the code snippets), the app is not linked to any backend. The form works fine, however, the Table does not refresh, even though the dataSource prop of the Table gets its content directly from the state and the state updates correctly - confirmed by logging and devtools. Curiously, the table refreshes with the new task when I initiate the implemented sorting, so my suspicion is that the Table somehow does not refresh its content from the state change, only on onChange hooks or something, but I'm feeling in a bit of a dead-end - any help would be greatly appreciated since I'm planning to use similar functionality in other Tables.
The structure is pretty simple, I have a TasksIndex.js with the Table as an individual component in TaskListTable.js
TaskListTable.js:
const TaskListTable = (props) => {
const { t } = useTranslation();
const [tableContent, setTableContent] = useState(props.tasks);
return (
<React.Fragment>
<Table
pagination={false}
dataSource={tableContent}
columns={[
{
title: t("tasks.name"),
key: "name",
render: (text) => {
return <p>{text.slug}</p>;
},
},
{
title: t("tasks.dateDue"),
dataIndex: "dateDue",
key: "dateDue",
sorter: (a, b) =>
new Date(a.dateDue).getTime() - new Date(b.dateDue).getTime(),
render: (dateDue) => {
let dateFormatted = moment(dateDue);
return <>{dateFormatted.format("LL")}</>;
},
defaultSortOrder: "ascend",
},
{
title: t("tasks.priority"),
key: "priority",
dataIndex: "priority",
render: (priority) => (
<React.Fragment>
{priority === "low" ? (
<Tag color="geekblue">{t("tasks.lowPriority")}</Tag>
) : (
""
)}
{priority === "normal" ? (
<Tag color="green">{t("tasks.normalPriority")}</Tag>
) : (
""
)}
{priority === "high" ? (
<Tag color="volcano">{t("tasks.highPriority")}</Tag>
) : (
""
)}
</React.Fragment>
),
sorter: (a, b) => {
const priorityOrder = ["low", "normal", "high"];
return (
priorityOrder.indexOf(a.priority) -
priorityOrder.indexOf(b.priority)
);
},
},
{
title: t("tasks.options"),
key: "options",
render: (item) => {
return (
<Checkbox value={item.id}>{t("tasks.setCompleted")}</Checkbox>
);
},
},
]}
></Table>
</React.Fragment>
);
};
export default TaskListTable;
TaskIndex.js:
const TasksIndex = () => {
const [isModalOpen, setModalOpen] = useState(false);
const [taskList, updateTaskList] = useState(taskListMock);
const [form] = Form.useForm();
const addTask = useCallback(
(values) => {
const newTaskList = taskList;
newTaskList.push({
id: taskList[taskList.length - 1] + 1,
slug: values.name,
description: values.description,
dateDue: values.dateDue.format("YYYY-MM-DD"),
priority: values.priority,
checked: false,
});
form.resetFields();
updateTaskList(newTaskList);
closeModal();
},
[taskList, form]
);
const openModal = () => {
setModalOpen(true);
};
const closeModal = () => {
setModalOpen(false);
};
const { t } = useTranslation();
return (
<React.Fragment>
<Title>{t("tasks.tasksOverviewHeader")}</Title>
<Row gutter={[16, 24]}>
<Col className="gutter-row" span={24}>
<TaskListTable tasks={taskList}></TaskListTable>
</Col>
</Row>
...
...
I finally fixed it - it seems that creating a new array and pushing the new task to it was not considered a state change (or perhaps a Table change trigger), unlike using the spread operator. The working code looks like this:
const addTask = (values) => {
const newTask = {
id: taskList[taskList.length - 1] + 1,
slug: values.name,
description: values.description,
dateDue: values.dateDue.format("YYYY-MM-DD"),
priority: values.priority,
checked: false,
};
updateTaskList([...taskList, newTask]);
closeModal();
form.resetFields();
};

Categories

Resources