So, I've got a bit of a doozy here. I've looked into trees and the like in react, and I'm fairly confident I can implement one, given the right data structure. The problem I'm running into is that I'm getting my data from an API that doesn't, at least natively, have the structure for a tree, so I'm trying to create that structure on the fly.
This is what the data I'm getting back from the API looks like:
const category = //could have children
{
"object_name":"B2B",
"data_provider_key":"bluekai",
"object_key": "bluekai-31",
"object_type":"category",
};
const segment = //will only be a child
{
"object_name":"B2B > Role/Title > Admin Exec",
"data_provider_key":"bluekai",
"object_key": "bluekai-1145",
"object_type":"segment",
"cpm_cost":2.500
};
And this is the logic that I'm using to try and manipulate the data from the API to add children/create parents, etc.
const asyncView = async function (segTree: string | undefined) {
const categoryDataCall = api.getBeeswaxSegmentView(categoryBody);
const segmentDataCall = api.getBeeswaxSegmentView(segmentBody);
const data = await Promise.all([categoryDataCall, segmentDataCall]);
const parent = categoryData.find( (el: any) => el.object_key === segTree);
const categories = data[0].payload;
if (categories.length >= 1) {
for (let i = 0; i < categories.length; i++) {
categories[i].children = [];
}
}
parent.children = categories.concat(data[1].payload);
setCategoryData(parent.children);
setParent(parent);
}
asyncView(e.currentTarget.dataset.segment_tree);
}
return (
<>
<div>PARENT: {parent.object_name}</div>
{categoryData.length === 0
? <div>No category data</div>
: categoryData.map((e: any) => {
if (e.object_type === 'segment') {
return (
<div data-segment_tree={`${e.object_key || "NULL"}`}
data-provider_key={`${e.data_provider_key}`}
>
{`Name: ${e.object_name} (${e.object_key}, $${parseFloat(e.cpm_cost).toFixed(2)} CPM)`}
</div>
)
}
return (
<div data-segment_tree={`${e.object_key || "NULL"}`}
data-provider_key={`${e.data_provider_key}`}
onClick={getCategoryAndSegmentData}
>
{`Name: ${e.data_provider_name || e.object_name}`}
</div>
)
})
}
</>
);
}
I haven't implemented the Tree part yet, but that's because I am fairly confident I'm not creating the relations between elements correctly in my logic/the logic breaks if there are multiple 'trees'/categories on a page (which there will be.)
Sorry if this is a bit much, but any help or just ideas on dynamically modifying the data from the API to fit the tree structure of child/parent relationships would be appreciated!
Edit in response to Ray Hatfield:
What's the relationship between a category and a segment?
Segments will always be children of Categories, and will never have children of their own. Categories can have other categories as children.
How do you establish which category a segment belongs to?
The object_key property from the Category object gets passed to the API call(s) (two calls are made: one for segments, and one for categories). This is the only relation between segments and categories - nothing else in the return data ties them together.
What is e?
I assume you mean in the e.currentTarget.dataset.segment_tree line.
e is the event object, which I'm using to create the queries and firing them off on click events. I'm storing the object_key in a data-attribute in the HTML, and then passing it to a handler to generate the categoryBody and segmentBody used in the asyncView() function.
For some reason I have to explicitly pass the e.currentTarget.dataset.segment_tree as an argument to the async function even though they're in the same scope, but all it's doing is allowing me to find the Category that was clicked in the existing array of data in state.
What is categoryData?
categoryData is the array of values ( that is currently in state. So, each time I hit the API I update category data to re-render everything.
Effectively, I'm finding the parent (category that was clicked) firing off the API calls to get all the subcategories/segments associated with the clicked categories object_key, and then adding a children prop to any incoming categories, and then setting the children of the last clicked element equal to the returned segments + categories, and then rendering.
e? What iscategoryData?