How to Initialise leaf/child stores of MobX State Tree - reactjs

My MobX State tree Model is like this
const ProductItem = types
.model({
name: types.string,
price: types.number
})
.actions(self => ({
changePrice(newPrice) {
self.price = newPrice;
}
}));
const ProductStore = types
.model({
items: types.optional(types.array(ProductItem), [])
})
.actions(self => ({
add(item) {
self.items.push(item);
}
}));
const AppStore = types.model('AppStore', {
productStore: types.maybeNull(ProductStore)
});
AppStore is root store.
I want to create AppStore and initialize below data for ProductStore. I've created below function to initialize and create store :
export const initializeStore = (isServer, snapshot = null) => {
if (isServer) {
AppStore.create({
.....
});
}
return store;
};
I'm not sure how ProductStore should be initialized inside AppStore.create() with this array :
items: [
{
name: 'Product 1',
price: 150
},
{
name: 'Product 2',
price: 170
}
]
any help would be appreciated.

The initial data can be given like this
AppStore.create({
productStore: {
items: [
{
name: 'Product 1',
price: 150
},
{
name: 'Product 2',
price: 170
}
]
}
});
as ProductStore is used under productStore key in your AppStore.

Related

How to update nested state in redux

I'm a bit stuck with redux. I want to create reducer that can update state onClick with data that provided in each button.
Here's my TabSlice.ts
interface ITabContext {
tabIndex: number,
posterUrlFetch: string,
tabData: {
fetchUrl: string;
title: string;
}[]
}
const initialState = {
tabIndex: 0,
posterUrlFetch: 'movie/popular',
tabData: [
{ fetchUrl: 'movie/popular', title: 'Trending' },
{ fetchUrl: 'movie/upcoming', title: 'Upcoming' },
{ fetchUrl: 'tv/popular', title: 'TV Series' },
]
}
const tabSlice = createSlice({
name: 'tab',
initialState: initialState as ITabContext,
reducers: {
changeTab(state, action: PayloadAction<ITab>) {
const newItem = action.payload;
return state = {
tabIndex: newItem.tabIndex,
posterUrlFetch: newItem.posterUrlFetch,
tabData: [
{ fetchUrl: newItem.posterUrlFetch, title: newItem.posterUrlFetch },
]
}
}
}
})
Then I dispatch changeTab in my component and create function onClick:
const click = () => dispatch(changeTab({
tabIndex: 1,
posterUrlFetch: 'movie/popular',
tabData: [
{
fetchUrl: 'tv/latest',
title: 'TV Latest'
},
{
fetchUrl: 'movie/popular',
title: 'Popular'
},
{
fetchUrl: 'movie/latest',
title: 'Latest'
},
]
}));
As i click some info updates, but in tabData I have only first object. How to make it to push all data to tabData, not only first one? Thanks!
Remove return state = {} from your reducer function and instead return the object as a whole.
return {
tabIndex: newItem.tabIndex,
posterUrlFetch: newItem.posterUrlFetch,
tabData: newItem.tabData,
};
For the payload's tabData you can pass newItem.tabData

How to Change Data in React

I want to create data from DATA to OPTIONS.
const DATA = [
{ name: 'aaa', id: 'happy' },
{ name: 'bbb', id: 'time' },
{ name: 'ccc', id: 'party' },
];
const OPTIONS =[{value:'aaa', label:'aaa'},
{value:'bbb', label:'bbb'},
{value:'ccc', label:'ccc'},
]
I need only name value in DATA.
so, using name value, I want to create OPTIONS.
Fuction Test(){
const DATA = [
{ name: 'aaa', id: 'happy' },
{ name: 'bbb', id: 'time' },
{ name: 'ccc', id: 'party' },
];
const OPTIONS =[{value:'aaa', label:'aaa'},
{value:'bbb', label:'bbb'},
{value:'ccc', label:'ccc'},
]
}
let newObject=[];
const createData = () => {
const arr = selectMainId.data.map(data => data.name);
arr.map(data => newObject.push({ value: data, label: data }));
console.log('newObj:', newObject);
};
console.log('newObj1:', newObject))
this case, I can get OPTIONS same data.
so, I can get newObject in createData console.
but I can't get newObject in Test console.
I don't know this issue.
Do you know effective way?
please help me.
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Clean and simplest way:
const DATA = [
{ name: 'aaa', id: 'happy' },
{ name: 'bbb', id: 'time' },
{ name: 'ccc', id: 'party' },
];
const OPTIONS = DATA.map(x => ({value: x.name, label: x.name }));
console.log(OPTIONS);
You just need to do
const createData = (data) => {
return data.map(d => ({name: data.name, label: data.name}))
};
const option = createData(data)

How to use spread operator to update array inside an object?

What the fetch returns is a list of items. I want to add those into state.
const [state, setState] = useState({
list: {
items: [],
}
});
fetch('http://example.com/list/')
// GET response: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
.then((resList) => resList.json())
.then((list) => {
list.forEach(({ name }) => {
const itemUrl = `https://example.com/list/${name}`;
fetch(itemUrl)
// GET responses:
// { name: 'foo', desc: '123' }
// { name: 'bar', desc: '456' }
// { name: 'baz', desc: '789' }
.then((itemRes) => itemRes.json())
.then((item) => {
setState((prevState) => ({
...prevState,
list: {
items: [...state.list.items, item]
},
});
})
})
}
})
console.log(state);
// result: [{ name: 'baz', desc: '789' }]
// but wanted: [{ name: 'foo', desc: '123' }, { name: 'bar', desc: '456' }, { name: 'baz', desc: '789' }]
In your case no need to use prevState in setState.
I prepared an example for you. Just be careful at using hooks.
https://codesandbox.io/s/recursing-wood-4npu1?file=/src/App.js:0-567
import React, { useState } from "react"
import "./styles.css"
export default function App() {
const [state, setState] = useState({
list: {
items: [
{ name: "foo", desc: "123" },
{ name: "bar", desc: "456" },
],
},
})
const handleClick = () => {
setState(() => ({
list: {
items: [...state.list.items, { name: "baz", desc: "789" }],
},
}))
}
return (
<div className="App">
<button onClick={handleClick}>Click Me </button>
<hr />
{JSON.stringify(state)}
</div>
)
}
You can't directly access the callback for useState hooks. This is how you can update state after fetching the data:
setState({
...state,
list: {
items:[...state.list.items, item]
},
});

Filter Array based on a property in the array of its objects

Given is following data structure
const list = [
{
title: 'Section One',
data: [
{
title: 'Ay',
},
{
title: 'Bx',
},
{
title: 'By',
},
{
title: 'Cx',
},
],
},
{
title: 'Section Two',
data: [
{
title: 'Ay',
},
{
title: 'Bx',
},
{
title: 'By',
},
{
title: 'Cx',
},
],
},
];
What i want to do ist to filter this list based on title property in the data array of each object.
An example would be to have the list where the title property of the childs starts with "B", so the list will look like that:
const filteredList = [
{
title: 'Section One',
data: [
{
title: 'Bx',
},
{
title: 'By',
}
],
},
{
title: 'Section Two',
data: [
{
title: 'Bx',
},
{
title: 'By',
}
],
},
];
What i tried so far was something like that:
const items = list.filter(item =>
item.data.find(x => x.title.startsWith('A')),
);
or
const filtered = list.filter(childList => {
childList.data.filter(item => {
if (item.title.startsWith('B')) {
return item;
}
return childList;
});
});
But i think i am missing a major point here, maybe some of you could give me a tip or hint what i am doing wrong
Best regards
Your issue is that you're doing .filter() on list. This will either keep or remove your objects in list. However, in your case, you want to keep all objects in list and instead map them to a new object. To do this you can use .map(). This way you can map your objects in your list array to new objects which contain filtered data arrays. Here's an example of how you might do it:
const list=[{title:"Section One",data:[{title:"Ay"},{title:"Bx"},{title:"By"},{title:"Cx"}]},{title:"Section Two",data:[{title:"Ay"},{title:"Bx"},{title:"By"},{title:"Cx"}]}];
const filterByTitle = (search, arr) =>
arr.map(
({data, ...rest}) => ({
...rest,
data: data.filter(({title}) => title.startsWith(search))
})
);
console.log(filterByTitle('B', list));

How to return an object with an array within an array

Need to return as an object or a better way of extracting data from the following data model.
const dataModel = {
data:[
{
id: '1234',
entity : [{
id: '1',
type: 'books'
}]
},
{
id: '1234',
entity : [{
id: '1',
type: 'books'
}]
}
]
};
I have tried the following code
const getBooksId = response.data.map(values => {
return values.entity.find(entity =>
entity.type === 'books'
);
}).filter( data => data !== undefined);
}
const getMagazineId = response.data.map(values => {
return values.entity.find(entity =>
entity.type === 'magazine'
);
}).filter( data => data !== undefined);
}
let getDataIntoObject = { bookId: getBooksId[0].id, magazineId: getMagazine[0].id }
The getDataIntoObject gives me the expected result which is the id of each entity but the code looks messy. Is there a better way of doing this?
Here is a version that looks a bit nicer:
const responseData = [
{
id: '123',
entity: [{
id: '1',
type: 'books'
}]
},
{
id: '456',
entity: [{
id: '2',
type: 'books'
}]
},
{
id: '789',
entity: [{
id: '3',
type: 'magazine'
}]
}
];
const entities = responseData.map(d => d.entity).flat();
const book = entities.find(e => e.type === 'books');
const magazine = entities.find(e => e.type === 'magazine');
const getDataIntoObject = {
bookId: book && book.id,
magazineId: magazine && magazine.id
};
console.log(getDataIntoObject);
...and handles a book or magazine not being found.

Resources