Svelte: Store Data Not Being Reactive When Component Changes Data and Vice Versa - store

I'm sure this is a super easy fix, but I'm having an issue where I setup a writable store, and it's mostly reactive, except when a component changes the data, the reactivity in the App file doesn't fire and vice versa. Here's the code:
App.svelte:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
let localData
data.subscribe((value) => {
localData = value;
});
</script>
<h2>In App.svelte</h2>
<p>Hello {localData.name}!</p>
<input name="name" type="text" bind:value={localData.name}>
<p>
{localData.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
Component.svelte:
<script>
import { data } from './store.js'
let localData
data.subscribe((value) => {
localData = value;
});
</script>
<input type="number" bind:value={localData.details.number}>
<p>Hello {localData.name}!</p>
<p>{localData.details.number}</p>
store.js:
import { writable } from 'svelte/store'
export let data = writable({
name: 'Bob Smith',
details: {
dob: '1982/03/12',
favoriteFoods: ['apples', 'pears', 'bourbon'],
number: 1
},
})
And, if you want to use it in the Svelte REP: https://svelte.dev/repl/164227336d6c4cc29f7ea0a15e89c584?version=3.44.3

You are subscribing to the data and putting it into a local variable and then bind to that. This means the store does not know that anything changed and updates won't be propagated. Two options:
First option: You get rid of the two way binding and update the store explicitely like this:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
let localData
data.subscribe((value) => {
localData = value;
});
function updateName(evt) {
const newName = evt.target.value;
data.update(value => ({...value, name: newName }));
}
</script>
<h2>In App.svelte</h2>
<p>Hello {localData.name}!</p>
<input name="name" type="text" value={localData.name} on:input={updateName}>
<p>
{localData.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
This is very explicit but also a bit boilerplate-y. We have Svelte's handy auto subscription feature, so let's use that instead. Second and prefered option:
<script>
import { data } from './store.js'
import Component from './Component.svelte'
</script>
<h2>In App.svelte</h2>
<p>Hello {$data.name}!</p>
<input name="name" type="text" bind:value={$data.name}>
<p>
{$data.details.number}
</p>
<h2>In Component.svelte</h2>
<Component />
Notice how we got rid of all the subscription boilerplate. $data accesses the current state of the store and since it's a writable store you can also write back to it that way. You can read more about stores in the docs: https://svelte.dev/docs#component-format-script-4-prefix-stores-with-$-to-access-their-values

Related

How to get form data onSubmission in React-remix by using useFetcher Hook using fetcher.submit()

I have a simple component with an input field and a submit button. I just want to get my data after i fill the input field and submit the form. by using useFetcher hook and fetcher.submit().
import { useEffect } from 'react';
import { useFetcher } from '#remix-run/react'
import { ActionFunction } from '#remix-run/node';
function fetchHook() {
const fetch = useFetcher();
useEffect(() => {
console.log("useEffect");
}, []);
return (
<div>
<h1> Use Fetcher Hook</h1>
<fetch.Form action='/fetcher' method='post'>
<div>
<input type="text" name="name" id="" />
<button type='submit' > Submit</button>
</div>
</fetch.Form>
</div>
)
}
export default fetchHook;
export const action: ActionFunction = async ({ request }) => {
}
What changes should i make to get my desired result. I am new to react-remix.

How to update Svelte writable store values with input tag

I have a writable store in Svelte with an object. I'd like to display the properties and be able to change the property values as a user.
I'm able to get the properties and values to display in input tags with an on:input event to update the value in the store, but I get an error saying the sampleStore.set isn't a function. I tried to add a custom update function to the store, but I'm getting the same error.
What's the best way to do this?
Sample code below
Store.js
import { writable } from 'svelte/store';
function createSampleStore() {
const sampleStore = writable({
property1a: 'value1a',
property1b: 'value1b',
etc...
}
return {
subscribe: sampleStore.subscribe,
updateValue: (propertyName, propertyValue) =>
sampleStore.update((o) => {
o[propertyName] = propertyValue;
return o;
}),
};
}
export const sampleStore = createSampleStore();
InfoDisplay.svelte
<script>
import {sampleStore} from './sampleStore.js';
const propertyNames = Object.keys($sampleStore);
$: console.log($sampleStore);
</script>
<ul>
{#each propertyNames as propertyName}
<li>
{propertyName}:
<input
on:input={(value) =>
sampleStore.updateValue(propertyName, propertyValue)}
bind:value={$sampleStore[propertyName]}
/>
</li>
{/each}
</ul>
I tried to adjust the values shown in the input tag and have the values in the store be updated, but I kept getting the .set is not a function.
The binding on the input value creates a get/set relationship, you should only pass the value in and use the event to get it out:
<input
on:input={e => sampleStore.updateValue(propertyName, e.target.value)}
value={$sampleStore[propertyName]} /> <!-- no bind here -->
You also do not need a custom store to do this and could just use a writable directly:
<input bind:value={$store[propertyName]} />
REPL

Nextjs: Cant render a component while using map over a array of objects. Objects are not valid as a React child

I dont know why when i want to render a component inside of a map function, basiclly i have a List component, and when i fetch data from an API with the email, etc.. from users i want that component to render that info. But i get the following error:
Unhandled Runtime Error
Error: Objects are not valid as a React child (found: object with keys {email, phone, nick}). If you meant to render a collection of children, use an array instead.
My List component looks like this:
import React from 'react'
export default function List(email, nick, phone) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email}</p>
<strong>Nick: </strong>
<p>{nick}</p>
<strong>Phone: </strong>
<p>{phone}</p>
</div>
)
}
And my List user page looks like this:
import React from 'react'
import Nav from '../../components/Nav/Nav'
import { useEffect, useState } from 'react';
import List from '../../components/User/List';
export default function index() {
const [users, setUsers] = useState([])
const fetchUsers = async () => {
const response = await fetch("http://localhost:3001/api/internal/users");
const data = await response.json();
console.log(data["data"])
setUsers(data["data"])
}
useEffect(() => {
fetchUsers()
}, [])
return (
<div>
<Nav />
{users.map(user => (
<List
email={user.attributes.email}
phone={user.attributes.phone}
nick={user.attributes.nick}
/>
))}
</div>
)
}
UPDATE 21 ABR
For some reason when i do this :
export default function List(email, phone, nick) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email.email}</p>
<strong>Nick: </strong>
<p>{email.phone}</p>
<strong>Phone: </strong>
<p>{email.nick}</p>
</div>
)
}
It works... Someone knows what it can be?
You are passing the props in a wrong way. Either use it as a single object in props or have all the props it inside {} using destructuring method.
export default function List({email, phone, nick}) {}
OR
export default function List(props) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{props.email}</p>
<strong>Nick: </strong>
<p>{props.phone}</p>
<strong>Phone: </strong>
<p>{props.nick}</p>
</div>
)
}

How to post form content to a card component

I was hoping someone could explain to me how I can get the information submitted in my form to show up in a card component? In a way it's a glorified todo list, but I want to know what best practice would be (ie grabbing the data from my database or from the store...?)
import React from 'react';
import { connect } from 'react-redux';
import { saveItem } from '../actions/index';
import { withRouter } from 'react-router-dom';
class AddItem extends React.Component {
render() {
console.log(this.props);
return(
<form onSubmit={(event) => {
event.preventDefault()
const input = {
name: event.target.itemName.value,
price: event.target.itemPrice.value,
description: event.target.itemDescription.value,
userEmail: this.props.currentUser.email
}
this.props.dispatch(saveItem(input))
event.target.itemName.value = ''
event.target.itemPrice.value = ''
event.target.itemDescription.value = ''
}}>
<label>
Item Name:
<br />
<input type="text" name="itemName" />
</label>
<br />
<label>
Price:
<br />
<input type="text" name="itemPrice" />
</label>
<br />
<br />
<label>
Description:
<br />
<textarea type="text" name="itemDescription"/>
</label>
<br />
<button>Submit</button>
</form>
)
}
}
const mapStateToProps = state => ({
currentUser: state.auth.currentUser
});
export default withRouter(connect(mapStateToProps)(AddItem));
so basically I need all of this info to show up in a container when the user hits submit.
These two options have pros and cons, the main differences are:
Using Redux Store:
Refreshing the page will erase all the data stored in your store
The data is in the client, means better performance
Harder to maintain as your apps grows -> store gets nested/larger.
Using Database:
the data is persisted and can be fetched whenever you want
fetching data takes a while and requires an endpoint + server call
much more organized
In general, use your store for temporary data, while your DB for persisting vital data.
In practice, you will find yourself using these methods interchangeably or even both simultaneously. e.g saving a copy of the data in the store before POSTing it into your DB, so the data will be still available for you to display it.
Last tip: https://hackernoon.com/shape-your-redux-store-like-your-database-98faa4754fd5

How to send data from parent to child component in Vue.js

I am new to vue.js and currently I am building an app for learning purposes.
What I want to do:
I have a parent component which has a bunch of buttons with different id's.
The child component will wait for those id's to be sent by the parent and it will decide what to display based on the id. Thats all.
I wont post the full code because it's too large but I have tried a bunch of stuff like props and state but honestly it is so confusing.
I come from React background and I am still confused.
Parent component
<template>
<button id="btn1">Show banana</button>
<button id="btn2">Show orange</button>
</template>
<script>
export default {
name: 'Parent',
data: function {
//something
},
props: {
// ?????
}
};
</script>
**Child component**
<template>
<p v-html="something.text">
</template>
<script>
export default {
name: 'Child',
data: function() {
something: ''
if(id from parent === id I want) {
something = object.withpropIneed
}
},
};
</script>
You need to map the data from parent and pass it to child, thats it!
In example i make passing a html string and binding that html received through 'fromParentHtml' prop mapped on child, so inside child component 'this.fromParentHtml' pass to exists because it is defined in props and every time you click in parent button executes the 'show' function and change the value from passed prop to child through parent 'html' data .. =)
<template>
<div>
Current html sent to child '{{html}}'
<br>
<button #click="show('banana')">Banana</button>
<button #click="show('orange')">Orange</button>
<button #click="show('apple')">Apple</button>
<!-- Create child component -->
<child-component :fromParentHtml="html"></child-component>
</div>
</template>
<script>
export default {
name: "test3",
components: {
'child-component': {
template: "<div>Child component... <br> <span v-html='fromParentHtml'></span> </div>",
//Child component map a prop to receive the sent html from parent through the attribute :fromParentHtml ...
props: {
fromParentHtml: {
required: true,
type: String
}
}
}
},
data(){
return {
html: ''
}
},
methods: {
show(fruit){
this.html = '<span>The fruit is ' + fruit + ' !</span>';
}
}
}
</script>
<style scoped>
</style>
If helped you please mark as correct answer! Hope it helps.
Edit 1:
Assuming you have webpack to work with single file components, to import another component just do:
<template>
<div>
<my-child-component></my-child-component>
</div>
</template>
<script>
//Import some component from a .vue file
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
//And pass it to your component components data, identified by 'my-child-component' in the template tag, just it.
'my-child-component': ChildComponent
},
data(){
},
methods: {
}
}
</script>
Just for the sake of it, I think you were looking for this:
<template>
<button id="btn1" #click = "id = 1">Show banana</button>
<button id="btn2" #click = "id = 2">Show orange</button>
<child-component :childid = "id"></child-component>
</template>
<script>
import childComponent from 'childComponent'
export default {
name: 'Parent',
data () {
return {
id: 0
}
},
components: {
childComponent
}
};
</script>
**Child component**
<template>
<p v-html="something.text">
</template>
<script>
export default {
name: 'Child',
props: {
childid: String
},
data: function() {
something: ''
if(this.childid === whatever) {
something = object.withpropIneed
}
},
};
</script>
Solved my problem by taking a different approach.
I have implemented state and my component behaves exactly as I wanted to.
I found this link to be helpful for me and solved my problem.
Thank you.

Resources