Assign prop values when doing a default export in ReactJS - javascript

I am having such a pain with such a small issue. I am integrating Launch Darkly which takes a certain number of parameters for it work during the export. My export is as follows:
export default withLDProvider({
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
})(App);
Now, clientSideID, userId, and site are part of my props which i need to assign to it.
I have tried the following:
export default (props) => {
const { auth: { userId, site } } = props.store.getState();
return withLDProvider({
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
})(App);
};
but i get the following error:
index.js:2178 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
in Component (created by Connect(Component))
in Connect(Component) (created by HotExportedConnect(Component))
in AppContainer (created by HotExportedConnect(Component))
in HotExportedConnect(Component) (at src/index.js:33)
in ErrorBoundary (at src/index.js:33)
help?

I'm confused, are you trying to create a component or a function? If you are creating a function, then you would not be sending props to it. If you are creating a component (call it like: <withLDProvider props={x} />), then maybe this will do what you want:
import React from "react";
const withLDProvider = props => {
const { userId, site } = props;
return (
{
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
}
)
}
export default withLDProvider;

Related

Returning a value from a js component

I'm using the Query component of React-Admin version 2.9 and I'm having trouble accessing its returned value. I've looked through github for usage examples, but with no luck thus far. It's an old version of the framework and the Query component appears to now be deprecated.
But I believe my issue may be a more generic one relating to my not fully grasping how to deal with js promises.
My function uses Query to make an api call and it looks like this:
const myfunction = (avalue) =>
<Query type="GET_LIST" resource="student" payload={{ filter: { id: avalue }}}>
{({ data, loading, error }) => {
if (loading) { return "loading"; }
if (error) { return "error"; }
return data.filter( i => i.studentType === 1 ).length
}}
</Query>
The result of the api call is an Integer value and I believe the above is obtaining it correctly.
Yet when I try to access the return value in this way ...:
console.log(myfunction(123));
... I don't get the actual value, but instead I get this:
{$$typeof: Symbol(react.element), key: null, ref: null, props: {…}, type: ƒ, …}
Any idea why the above is getting returned instead of the actual value and how to resolve this?
Your function is a React component. React components, when executed, return a React element. They are designed to be rendered in JSX, not to be called directly. See https://reactjs.org/docs/components-and-props.html#function-and-class-components for details.
If you want to execute a query in the JS (not JSX) part of a component, in react-admin 2.9 you must use the withDataProvider decorator.
Here is an example usage:
import {
showNotification,
UPDATE,
withDataProvider,
} from 'react-admin';
class ApproveButton extends Component {
handleClick = () => {
const { dataProvider, dispatch, record } = this.props;
const updatedRecord = { ...record, is_approved: true };
dataProvider(UPDATE, 'comments', { id: record.id, data: updatedRecord })
.then(() => {
dispatch(showNotification('Comment approved'));
dispatch(push('/comments'));
})
.catch((e) => {
dispatch(showNotification('Error: comment not approved', 'warning'))
});
}
render() {
return <Button label="Approve" onClick={this.handleClick} />;
}
}
ApproveButton.propTypes = {
dataProvider: PropTypes.func.isRequired,
dispatch: PropTypes.func.isRequired,
record: PropTypes.object,
};
export default withDataProvider(ApproveButton)

I want to use this. $ axios with Vuex constants

What I want to come true
I use this.$axios many times, so I tried to put it in a constant, but it doesn't work.
I read the official docs but didn't understand.
Is it because this isn't available in the Nuxt.js lifecycle?
Code
url.js
export const AXIOS_POST = this.$axios.$post
export const POST_API = '/api/v1/'
export const POST_ITEMS_API = '/api/v1/post_items/'
Vuex
import * as api from './constants/url.js' // url.js in this.
export const state = () => ({
list: [],
hidden: false
})
export const mutations = {
add (state, response) {
state.list.push({
content: response.content,
status: response.status
})
},
remove (state, todo) {
state.list.splice(state.list.indexOf(todo), 1)
},
edit (state, { todo, text }) {
state.list.splice(state.list.indexOf(todo), 1, { text })
},
toggle (state, todo) {
todo.status = !todo.status
},
cancel (state, todo) {
todo.status = false
},
// アクション登録パネルフラグ
switching (state) {
state.hidden = !state.hidden
}
}
export const actions = {
post ({ commit }, text) {
//I want to use it here
this.$axios.$post(api.POST_ITEMS_API + 'posts', {
post_items: {
content: text,
status: false
}
})
.then((response) => {
commit('add', response)
})
}
}
Error
Uncaught TypeError: Cannot read property '$axios' of undefined
Since your file is located into a constants directory, you should probably use some .env file.
Here is a guide on how to achieve this in Nuxt: https://stackoverflow.com/a/67705541/8816585
If you really want to have access to it into a non .vue file, you can import it as usual with something like this
/constants/url.js
import store from '~/store/index'
export const test = () => {
// the line below depends of your store of course
return store.modules['#me'].state.email
}
PS: getters, dispatch and everything alike is available here.
Then call it in a page or .vue component like this
<script>
import { test } from '~/constants/url'
export default {
mounted() {
console.log('call the store here', test())
},
}
</script>
As for the lifecyle question, since the url.js file is not in a .vue file but a regular JS one, it has no idea about any Vue/Nuxt lifecycles.

Still getting undefined to a property in node with react project

I have three different components that within them are using a component called StripeCheckout and one of the properties of StripeCheckout is description which I currently have as a string:
import React, { Component } from "react";
import StripeCheckout from "react-stripe-checkout";
import { connect } from "react-redux";
import * as actions from "../actions";
class SunnySampler extends Component {
render() {
return (
<div>
<StripeCheckout
name='Microurb Farms'
amount={this.props.amount}
description='Sunny Sampler Box'
shippingAddress
billingAddress={false}
zipCode={true}
token={(token, amount) =>
this.props.handleToken(token, this.props.amount)
}
stripeKey={process.env.REACT_APP_STRIPE_KEY}
/>
</div>
);
}
}
export default connect(null, actions)(SunnySampler);
SunnySampler is just one of the three components making use of StripeCheckout. Each has its own amount property dynamically coded and passed down to the express api and yet I cannot seem to pass down the description property successfully.
The challenge also is that each description property is different depending on which component was selected.
So I was able to pass in the amount dynamically here:
const tiers = [
{
title: "Half pound boxes",
price: "10",
description: [
"Sunflower Shoots",
"Pea Shoots",
"Radish Shoots",
"Broccoli Shoots",
],
buttonText: <HalfPound amount={1000} />,
buttonVariant: "outlined",
},
{
title: "Grasses",
subheader: "Tray",
price: "15",
description: ["Wheatgrass", "Barleygrass"],
buttonText: <Grasses amount={1500} />,
buttonVariant: "contained",
},
{
title: "Sunny Sampler Box",
price: "20",
description: [
"6oz Sunflower",
"2oz Broccoli",
"3oz Sweet Pea",
"2oz Radish",
],
buttonText: <SunnySampler amount={2000} />,
buttonVariant: "outlined",
},
];
this is inside of Dashboard.js, then in my action creator I pass it in like so:
export const handleToken = (token, amount) => async (dispatch) => {
const res = await axios.post("/api/stripe", { token, amount });
dispatch({ type: FETCH_USER, payload: res.data });
};
Inside each of those payment type of components it looks like so:
import React, { Component } from "react";
import StripeCheckout from "react-stripe-checkout";
import { connect } from "react-redux";
import * as actions from "../actions";
class SunnySampler extends Component {
render() {
return (
<div>
<StripeCheckout
name='Microurb Farms'
amount={this.props.amount}
description='Sunny Sampler Box'
shippingAddress
billingAddress={false}
zipCode={true}
token={(token, amount) =>
this.props.handleToken(token, this.props.amount)
}
stripeKey={process.env.REACT_APP_STRIPE_KEY}
/>
</div>
);
}
}
export default connect(null, actions)(SunnySampler);
and finally my backend api:
const keys = require("../config/keys");
const stripe = require("stripe")(keys.stripeSecretKey);
module.exports = (app) => {
app.post("/api/stripe", async (req, res) => {
const { amount, token } = req.body;
// const description = req.body.data.description;
const charge = await stripe.charges.create({
amount: amount,
currency: "usd",
source: token.id,
});
console.log(charge);
});
};
I tried taking the same approach I took to the amount property with the description property and variations of it and I am still getting undefined.
Originally, inside the action creator I had passed in description to it and then inside the handleToken I had passed in this.props.description and then inside the api route on the backend I had req.body.description which should have worked, but I got undefined.
When I console log req.body I see in the data structure description: null, despite having passed a string into the description property inside of StripeCheckout component. I cannot explain why that is.

How can I update state from select options?

My app contains main component, which render data, received from store, at list. Child component allow to select an options. And after user made a choice (one of options at dropdown list), object in store should be updated accordingly. Further, when I refresh the page, I expect updated list to be render.
Main component (TableMain):
import OperationSelect from "./operationSelect";
const mapStateToProps = (store) => {
return {itemsProp: store.fetch.items}
};
class TableMain extends React.Component {
// constructor
getOperationItems = function () {
this.props.itemsProp.map((item, index) => {
return (
<li>key={index} item={item}</li>
);
});
};
render() {
return <div>
{this.getOperationItems()}
<OperationSelect />
</div>;
}
}
export default connect(mapStateToProps)(TableMain)
Initial state:
export default {
items: [
{
'Date': null,
'Operation': 'revenue',
}
]
}
Update-action:
export function selectOperation(payload) {
return {
type: 'SELECT',
payload: payload,
};
}
I omit get-action, because its work well.
Update reducer:
import initialState from '../constants/initialState';
export default function update(state = initialState, action) {
switch (action.type) {
case 'SELECT':
return {
...state,
[action.payload.key]: action.payload.value
};
default:
return state;
}
}
Combine-reducers:
import {combineReducers} from 'redux';
import fetch from '../reducers/fetchReducer';
import update from '../reducers/updateReducer';
const rootReducer = combineReducers({fetch, update});
export default rootReducer;
And child-component for select-operation providing:
const mapDispatchToProps = (dispatch) => {
return {
selectOperation: (input) => dispatch({type: 'SELECT', payload: input})
}
};
const mapStateToProps = (store) => {
return {itemsProp: store.fetch.items}
};
class OperationSelect extends React.Component {
// constructor
handleChange(event) {
this.props.selectOperation({
key: 'Operation',
value: event.target.value
});
console.log(`items = ${JSON.stringify(this.props.itemsProp)}`);
};
render() {
return (
<label>
<select onChange={this.handleChange}>
<option selected="select value"></option>
<option value="value1">Option1</option>
<option value="value2">Option2</option>
</select>
</label>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(OperationSelect).
Container component exists, but omitted.
When I simply load a page (without any use choice) everything is well. App fetch from store initial-state data: {'Date': null,'Operation': 'revenue'}.
When I'm trying to select an option in dropdown list (for example, "value1"), I expect, updated data will be received from redux-store. For example - {'Date': null,'Operation': 'value1'}. But contrary to expectations I receive from store old an value - {'Date': null,'Operation': 'revenue'}.
In Browser-Console I see the following message:
index.js:1437 Unexpected key "items" found in preloadedState argument passed to createStore. Expected to find one of the known reducer keys instead: "fetch", "update". Unexpected keys will be ignored.
Please, advise me, how could I update object-state in redux-store from Select dropdown-list?
You can try using "redux-persist" in your application. This package delays the app UI rendering until your persisted state has been retrieved and saved to redux after page refresh. You can read the documentation at https://www.npmjs.com/package/redux-persist
Alternatively, you can configure the dropdown in a way that it doesn't refresh the page, just refresh the affected values on the page and it will give more cleaner UI experience.

Apollo/graphQL: How to use optimistic UI for a mutation of a nested react component?

As shown below I'm getting my data in my nextJS application in the pages/article.js using a graphQL query.
This data is passed down to another react component, which gives me a list of checkboxes.
Selecting a checkbox is calling a mutation to store the ID of the selected checkboxes in the DB.
To get the content updated, I'm using refetchQueries to call the main query again, which will pass the data down to the current component.
So far everything is working. Now I would like to get this stuff realtime using optimistic UI - which makes me some problems...
Replacing the refetchQueries with
update: (store, { data: { getArticle } }) => {
const data = store.readQuery({
query: getArticle,
variables: {
id: mainID
}
})
console.log(data)
}
runs me to the error TypeError: Cannot read property 'kind' of undefined which comes from readQuery.
I don't see what I'm doing wrong. And this is just the first part to get optimisic UI..
pages/article.js
import Article from '../components/Article'
class ArticlePage extends Component {
static async getInitialProps (context, apolloClient) {
const { query: { id }, req } = context
const initProps = { }
// ...
return { id, ...initProps }
}
render () {
const { id, data } = this.props
const { list } = data
return (
<Article
mainID={id}
list={list}
/>
)
}
}
export default compose(
withData,
graphql(getArticle, {
options: props => ({
variables: {
id: props.id
}
})
})
)(ExtendedArticlePage)
components/Article.js
import { getArticle } from '../graphql/article'
import { selectMutation } from '../graphql/selection'
export class Article extends Component {
checkboxToggle (id) {
const { mainID, checkboxSelect } = this.props
checkboxSelect({
variables: {
id
},
refetchQueries: [{
query: getArticle,
variables: {
id: mainID
}
}],
})
}
render () {
const { list } = this.props
return (
list.map(l => {
return (<Checkbox onClick={this.checkboxToggle.bind(this, l.id)} label={l.content} />)
}
)
}
}
export default compose(
graphql(selectMutation, { name: 'checkboxSelect' })
)(Article)
You have a variable shadowing issue in your update code, it seems that you're using the same name getArticle for both your query and the mutation result nested in data.
This is why your call to readQuery fails, the query params you need to provide resolves to the mutation result and not the actual query, hence the TypeError: Cannot read property 'kind' of undefined.
You just need to name your query with another identifier like getQueryArticle.

Categories