react-beautiful-dnd throws error when ordering the second time - reactjs

I have bean following the official tutorial for react-beautiful-dnd from egghead.io. On lesson 5 persisting the reordering my implementation throws all the time an error but only the second time when I try to reorder the top item. It works fine when I reorder the first time.
This is my branch specific to this question: https://github.com/bogdan-marian/my-react-beautiful-dnd/tree/002-property-id-question
The error that I get when I order the second time is:
TypeError: Cannot read property 'id' of undefined
src/Column.js:31
# and row 31 shows
<Task key={task.id} task={task} index={index} />)}
I'm not able to spot what is wrong with my implementation.

I found the problem. There was a typo bug in my initialData.js
My second task had the id taks-2 instead of task-2. The columns on the other hand was set to point to the task-2. This is how initial data looked before the fix
const initialData = {
tasks: {
'task-1': {id: 'task-1', content: 'Take out the garbage'},
'task-2': {id: 'taks-2', content: 'Watch my favorite show'},
'task-3': {id: 'task-3', content: 'Charge my phone'},
'task-4': {id: 'task-4', content: 'Cook dinner'},
},
columns: {
'column-1':{
id:'column-1',
title:'To do',
taskIds:['task-1','task-2', 'task-3', 'task-4']
}
},
// Facilitate reordering of the columns
columnOrder:['column-1']
}
All I had to do was to updated my second task id to task-2.

Related

Tell apollo-client what gets returned from X query with Y argiments?

I have a list of Items of whatever type. I can query all of them with query items or one with query item(id).
I realize apollo can't know what will be returned. It knows the type, but it doesn't know the exact data. Maybe there is a way not to make additional request? Map one query onto another?
Pseudo-code:
// somewhere in Menu.tsx (renders first)
let items = useQuery(GET_ITEMS);
return items.map(item => <MenuItemRepresenation item={item} />);
// meanwhile in apollo cache (de-normalized for readability):
{ ROOT_QUERY: {
items: [ // query name per schema
{ id: 1, data: {...}, __typename: "Item" },
{ id: 2, data: {...}, __typename: "Item" },
{ id: 3, data: {...}, __typename: "Item" },
]
}
}
// somewhere in MainView.tsx (renders afterwards)
let neededId = getNeededId(); // 2
let item = useQuery(GET_ITEM, { variables: { id: neededId } } );
return <MainViewRepresentation item={item} />;
Code like this will do two fetches. Even though the data is already in the cache. But it seems apollo thinks on query level. I would like a way to explain to it: "If I make item query, you need to look over here at items query you did before. If it has no item with that id go ahead and make the request."
Something akin to this can be done by querying items in MainView.tsx and combing through the results. It might work for pseudo-code, but in a real app it's not that simple: cache might be empty in some cases. Or not sufficient to satisfy required fields. Which means we have to load all items when we need just one.
Upon further research Apollo Link looks promising. It might be possible to intercept outgoing queries. Will investigate tomorrow.
Never mind apollo link. What I was looking for is called cacheRedirects.
It's an option for ApolloClient or Cache constructor.
cacheRedirects: {
Query: {
node: (_, args, { getCacheKey }) => {
const cacheKey = getCacheKey({
__typename: "Item",
id: args.id,
});
return cacheKey;
},
},
},
I'd link to documentation but it's never stable. I've seen too many dead links from questions such as this.

react-data-grid, cannot read property 'map' of undefined

I am attempting to create a data table with react-data-grid with my own data. First I attempted to recreate the getting started example and I get the error
"TypeError: Cannot read property 'map' of undefined" at
.../node_modules/react-data-grid/dist/react-data-grid.js:1094.
I installed everything properly, I'm not sure why this is happening when I'm literally just following the tutorial.
Initially started with my own data, then I used the same exact data from the example and it still has the same error.
Using tutorial at this link: https://adazzle.github.io/react-data-grid/docs/quick-start
render(){
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' },
{ key: 'count', name: 'Count' } ];
const data = [{id: 0, title: 'row1', count: 20}, {id: 1, title: 'row1',
count: 40}, {id: 2, title: 'row1', count: 60}];
return (
<div>
<ReactDataGrid>
columns={columns}
rowGetter={i => data[i]}
rowsCount={3}
minHeight={150}
</ReactDataGrid>
</div>
);
}
Your issue is you are closing the tag before trying to pass props. aka
<ReactDataGrid>
^-------------^
open close
This means that the props would be treated as "children" in the React ecosystem (Anything that is inbetween the component tags is considered children, I'm a little surprised this compiles, partly why I like to use typescript to get syntax issue warnings like this).
In React, the way you pass properties is on the tag itself before closing it.
<ReactDataGrid prop1={something}>
---------------^-----------------
^ prop on component before closing tag
To fix your current implementation just change it to this :)
<ReactDataGrid
columns={columns}
rowGetter={i => data[i]}
rowsCount={3}
minHeight={150}
/>
See a working example here

Enzyme+React expect component string - failed to parse selector

So I have this test case which I need to solve. Background is updating dev environment to newer version and after that a lot of our tests broke.
Here I have a weird case which results in:
"Failed to parse selector: Label price detail 1"
This is how the test snippet looks like, I hope I've added all that is necessary.
it('Should render with price and one addon', () => {
data.addonHeaderName = 'addonHeaderName';
data.addons.push(
{
price: {
label: 'Addon text 1',
value: 50.33,
unit: 'dollars',
vat: 'excl'
},
discount: {
label: 'Addon text 2',
value: 11.43,
unit: 'dollars',
vat: 'excl'
},
future: false,
addonIcon: 'icon',
ecoText: 'Addon eco text',
linkUrl: 'http://testaddonlink.com'
}
);
data.contract.prices.push(
{
id: 'price',
label: 'Label price detail 1',
unit: 'dollars',
value: 4.03
},
{
id: 'Label price detail 2',
label: 'Discount',
unit: 'dollars',
value: -3.00
}
);
const component = shallow(
<MyContract
data={data}
andSomeOtherStuff={otherStuff}
/>
);
expect(component).toMatchSnapshot();
expect(component.find('Label price detail 1')).toBeTruthy();
expect(component.find('Label price detail 2')).toBeTruthy();
expect(component.find('Addon text 1')).toBeTruthy();
expect(component.find('Addon text 2')).toBeTruthy();
expect(component.find('Addon eco text')).toBeTruthy();
If I comment out the first expectation, it hits the next one, and then the other one etc etc.
Earlier we ran Enzyme 2.9.1 together with enzyme-adapter-react-15 (and of course React 15) but since we've upgraded to React 16 we also need to update a few other dependencies such as this one. And then shit hit the fan.
Now we're on Enzyme 3.8.0, enzyme-adapter-react-16.3 and React 16.3.x.
I've been fiddling around with trying to get it as a string instead but no bueno. Any ideas on what I'm missing here?
Enzyme find works with css selectors so if you would like to search on the label there you should probably use something like:
component.find('[label="Label price detail 1"]')
Additionally I believe this will always be truthy no matter if it's found or not. (Not sure on that one though).
I usually use .toHaveLength(1) to check if it gets rendered!
I had this before, this looks like a typing error. Confirm the strings.

How to reuse subresource data for referenced inputs in React-admin?

In react-admin documentation the use of ReferenceArrayInput is for this kind of data structure:
{
id: 1,
groups: [1, 2, 3]
}
And then:
<ReferenceArrayInput source="groups" reference="groups" allowEmpty>
<SelectArrayInput optionText="name"/>
</ReferenceArrayInput>
Using a custom json data provider, it will be make this request:
https://example.com/api/groups/?ids=[1,2,3]
or if the API doesn't support WHERE IN, it will be do individual calls for each id:
https://example.com/api/groups/1
https://example.com/api/groups/2
https://example.com/api/groups/3
But if I have the following data structure:
{
id: 1,
name: "Pepito Perez",
groups: [
{ id: 1, name: "HR"},
{ id: 2, name: "IT"},
{ id: 3, name: "FINANCE"}
]
}
I have the name field already, so I don't want make additional requests.
When I go to the edit view react-admin performs almost 70 requests unnecessary.
How can I avoid that? there's a way to reuse the data?
Also is tricky use ReferenceArrayInput component with an array of objects, I have to add a nonsense format prop to make it works: format={v => (v ? v.map(i => (i.id ? i.id : i)) : [])}
Guess it's related to the first problem.
Thanks in advance!
If the choices is not meant to be fetched, ReferenceInput is not what you want. You need only a SelectInput with programmatic setted choices. You can achieve that with FormDataConsumer:
<FormDataConsumer>
{({ formData, ...rest }) =>
<SelectArrayInput
source="selectedGroups"
optionText="name"
choices={formData.groups}
{...rest}
/>
}
</FormDataConsumer>
Note a different source, probably setting as groups, equal to choices "source", after first selected group, would result in a re-render, letting choices values equal to the single selected group.
That's almost exactly the use case of FormDataConsumer in documentation:
https://marmelab.com/react-admin/Inputs.html#linking-two-inputs

VueJS Array update bug

I have a JSFiddle below to explain my problem but basically I have an array called tiles which has a title. When the instance is created() I add a field to this array called active
I then output this array in an <li> element and loop through it outputting the title and active objects. My problem is as you can see in the fiddle when I run v-on:click="tile.active = true" nothing happens to the active state written in the <li> element
but if I run v-on:click="tile.title = 'test'" it seems to update the active object and the title object.
Its strange behaviour I can't seem to work out why. Does anyone have any ideas?
https://jsfiddle.net/jgb34dqo/
Thanks
It's to do with Vue not knowing about your properties, change your array to this:
tiles: [
{
title: 'tile one',
active: false
},
{
title: 'tile two',
active: false
},
{
title: 'tile three',
active: false
}
]
This allows Vue to know about the active property and in turn it knows to monitor that variable.
It's worth looking at this link about Vue Reactivity as it helps with understanding how and when data will change automagically.
If you must add the properties after
take a look at $set. It allows you to add props to an object that then get watched by vue. See this fiddle, notice the change:
this.tiles.forEach(function(tile) {
// Tell vue to add and monitor an `active` prop against the tile object
this.$set(tile, 'active', false);
}.bind(this))

Resources