Using Axios to get multi-dimensional array object in React-Native - react-native

Good day
I am currently trying to learn React-Native through a Udemy course, but I am stuck at a stage where I need to get a multi-dimensional array from a source using Axios. Unfortunately, the end-point provided by the course is no longer available, but I recreated the data exactly as it was displayed in the course video. I then hosted the data in txt file on one of my own websites just so that I can continue with the course.
I am using VSCode for the coding and Android Studio for testing and debugging.
The problem now is that if I get the multi-dimensional array, it comes through just as a long string. If I flatten the array and remove the nested array, leaving me with a one dimensional array, then it pulls in the data as an array. So, it seems as if the problem is with the nested array.
This is the code that I am using to get the data:
import React, {Component} from "react";
import {Text, View} from 'react-native';
import axios from "axios";
class CarList extends Component {
constructor() {
super();
this.state = {carList:[] };
}
componentDidMount() {
axios.get('https://freedomsoftware.co.za/wp-content/uploads/2023/02/cars-file1.txt').then((response) =>{
this.setState({carList: response.data});
});
}
render () {
console.log(this.state);
return (
<View>
{<Text>Car List</Text>}
</View>
);
}
}
export default CarList;
The hosted txt file can be found here: https://freedomsoftware.co.za/wp-content/uploads/2023/02/cars-file1.txt
I know there is still a lot of code missing, such as error checking and so on, but this is just to get started and I assume I will still get to the error checking section in the course.
I have tried various changes to the file to see if it works, such as removing the "-", copying the array directly into the constructor and then fixing any syntax errors that VSCode points out and then copying it back into the txt file, but nothing seems to work. The moment I add the nested array, it comes through as a string instead as an object.
I also did try to contact the course instructor together with other students, but unfortunately there hasn't been any response from them.
I also did try to find solutions online and here on stackoverflow, but I just couldn't find something similar to this issue anywhere.
I am obviously missing something small or stupid that I just don't know about, but any help or pointers will be greatly appreciated.

Related

How to reload a component or call a function after action in another component with React Native

I use React Native and Expo to develop an application on mobile and tablet.
The objective is to be able to answer a questionnaire where several questions are divided into various categories. A question may have a category or not, so they don't really follow each other in the code.
I use a loop to display my categories, with its questions inside. Questions are components, categories too.
When I answer a question, sometimes I want to reload another question specifically (or several). After answering my question, I have a list of questions I want to reload.
I would like either to launch a function in the component, or to reload it entirely.
How do I reload the question component, which may be quite far from the one I acted on?
Thanks for your help !
I wanted to listen with UseEffect for the modification of my global variable, but it doesn't work. Also, I can't fully reload my page either. I would like to specifically reload the question component or run the function.
What I have already tried:
Reloading the page entirely from my screen with a function in global, didn't work (
I have a lot of elements so I would like to avoid reloading everything)
Listen with useEffect the change of my list of questions to modify to check if my id was in it, but the listening is not done
I can't send functions or other elements in the props of my question because they can be in different components (category or other) so too far away.
Question Component (simplified) :
export default function RealisationQuestionComponent(props){
//When action in Question A
function changeCheckA(value) {
[...]
if (props.question.questions_impactees !== undefined) {
global.questions_impactees = props.question.questions_impactees;
}
}
//Effect in Question B
useEffect(() => {
[my function or reload entire component]
}, [global.questions_impactees]);
return (
<>...</>
)
EDIT :
Following the answer, I tried to use useContext to retrieve my information, but it tells me Can't find variable : RealContext
What i would like to do :
https://www.w3schools.com/react/showreact.asp?filename=demo2_react_context2
What I have done :
My screen AuditRealisationScreen
const RealContext = createContext();
const [listIdVictimes, setListIdVictimes] = useState('please test');
[...]
return (
<RealContext.Provider value={listIdVictimes}>
<RealisationChapitreComponent/>
</RealContext.Provider>
)
RealisationChapitreComponent > [...] > RealisationQuestionComponent
In my component RealisationQuestionComponent
const listTest = useContext(RealContext);
[...]
return (
<Text> {listTest} </Text>
)
Can it work this way?
Use [contexts][1]. Using [reducers][2] with context would be more flexible and organised.
If you have a lot of states to manage with mess of siblings and parent-child and child-parent relations then using [Redux][3] would give you more control to manage those components and its states
What I used do for
How to reload a component or call a function after action in another
component with React Native
const context = ... // declare
and then
// import context
const App=()=>{
...
return(
<Context.Provider value={your functions, data, states, props whatever you want}>
{{ ...child components }}
<Context.Provider/>
)
}
You can play with these contexts usage to achieve your goal
[1]: https://reactjs.org/docs/hooks-reference.html#usecontext
[2]: https://reactjs.org/docs/hooks-reference.html#usereducer
[3]: https://redux.js.org/introduction/why-rtk-is-redux-today#what-is-redux

Best practice to write minimal code when using vuejs vee-validate with composition api in vuejs3

I have gone through the composition api docs for vee-validate, and I can definitely get my validation working on my forms if I follow the pattern described in their docs.
I don't feel comfortable however doing it as documented there, as I just feel I'm writing too much code for each form, and I do not want to repeat myself.
So I've been experimeting a bit with how I can optimise this, and this is what we currently came up with, but I'm a bit stuck now.
You can see the code example on https://codesandbox.io/s/restless-star-1qwgb, but I'll walk you through.
Consider we want to create a form for creating a new Invoice.
An invoice is typically composed of the Invoice model with a number of InvoiceElements attached to it. (the invoice lines)
In our vueJs codebase, we have javascript classes representing each model that we need to work with, so you'll find a class Invoice and a class InvoiceElement, both extending BaseModel which already providers some basic functionality.
On each mode, we have defined a static method returning a yup validation schema, e.g.:
import * as yup from "yup";
import BaseModel from "./BaseModel";
import InvoiceElement from "./InvoiceElement";
export default class Invoice extends BaseModel {
static get validationSchema() {
return yup.object().shape({
due_date: yup.date().min(new Date()).default("2021-09-30"),
reference: yup.string(),
elements: yup
.array()
.of(InvoiceElement.validationSchema)
.default([InvoiceElement.validationSchema.getDefault()])
});
}
}
As you can see, we also define default values for each of the schema fields.
This allows us to do the following in our form component:
setup() {
let { handleSubmit, errors, values } = useForm({
validationSchema: Invoice.validationSchema,
initialValues: Invoice.validationSchema.getDefault(),
validateOnMount: false,
});
let addLine = () => {
values.elements.push(InvoiceElement.validationSchema.getDefault());
};
let submitForm = handleSubmit((values) => {
alert("form was valid and we submit data here");
});
return {
values,
errors,
addLine,
submitForm,
};
}
Okay - I'm very happy with this as we now have:
values which is reactive and I can just bind to my inputs using ```
errors which has my errors
When I submit the form, it correctly triggers vee-validate's handleSubmit() method and my errors get correctly updated.
My main issue with this approach now is how to trigger the validation of the fields when they get updated. The main goal is to avoid having to write too much code using the useField() composable.
I know I'm not following the proposed pattern, but it just kept feeling as if we were writing too much code, and we seem quite close to a good pattern, but I just don't get the last bits...
Maybe someone on here does though :-)
Generally, the docs are only meant to show you "how it works", but I do agree that useField is very verbose if used incorrectly. Using it for models isn't the intended use-case.
For example:
// Very verbose and not the intended use-case
const { value: email } = useField(...);
const { value: password } = useField(...);
The main purpose of useField is to help create input components that can be validated, that if you are willing to couple your form components with vee-validate which I find reasonable in 80% of situations.
To try to answer your issue, since you want to avoid using useField you could actually make use of the other useXXX functions called composition helpers. Like useValidateField which creates a function for you that can validate any field given it was created in a child of a useForm component.
const validate = useValidateField('fieldName');
validate(); // triggers validation on the field

The purpose of StyleSheet.create in React Native

I wanted to ask the community about the changes in StyleSheet.create in React Native.
Before:
I have reviewed the past questions about this topic, such as this question, but they all have been answered pretty a long time ago (apart from this answer, but I wanted to have something definite) and a lot has changed since.
Before StyleSheet was creating a unique id for the styles, mainly for performance optimisations. If you wanted to get the styles out of the created styles object, you should have used the flatten method. The majority of the answers reference this flatten method and you could not access styles property as if it was a normal object.
E.g.
const styles = StyleSheet.create({
modalContainer: {
width: 100,
backgroundColor: 'white',
padding: 5,
},
You could not access the padding styles like styles.modalContainer.padding;
Currently:
However, the behaviour of this has changed. This is the source code of StyleSheet from the React Native team. Just copying the create method:
create<+S: ____Styles_Internal>(obj: S): $ObjMap<S, (Object) => any> {
// TODO: This should return S as the return type. But first,
// we need to codemod all the callsites that are typing this
// return value as a number (even though it was opaque).
if (__DEV__) {
for (const key in obj) {
StyleSheetValidation.validateStyle(key, obj);
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
return obj;
},
};
Which is just returning the object passed to create without doing anything to it. So you can actually access the styles as styles.modalContainer.padding;
Maybe I don't understand clearly the TODO, but this method has been coded this way at least since RN 0.57 and I don't know whether they are going to change it back.
My question:
Is there any sense in using StyleSheet.create anymore?
Thanks in advance for sharing your opinions!
Stylesheet is generally used to create a global style in react native and add it to the respective views which requires to style the objects.
Some widgets like TextInput, Text, Button cannot apply almost all the css styles in the react native.
So, in those cases what you can do is you can wrap those widgets with and then can create global StyleSheets using StyleSheet.create() method to globally use and reduce your headache.
So the conclusion for your question can be summarized as the Stylesheet.create() can be helpful to improve the performance while styling your multiple views using the same style will create a new object every time for each one.
While Stylesheet.create() will act as a single global object for all the views which are using it to style themselves resulting performance/memory optimisation.
I've never heard of this flatten() being necessary like you described. In fact, in the React Native repo in the very first commit, there was an example provided:
Examples/Movies/MovieCell.js:
https://github.com/facebook/react-native/commit/a15603d8f1ecdd673d80be318293cee53eb4475d#diff-4712aeb2165b3c0ce812bef903be3464
In this example, you can see var styles = StyleSheet.create({..}); being used in its present flavor and at that moment in 2016 you can see styles being referenced in the components as styles.styleName.
Additionally in the StyleSheet class here is create from the initial commit:
class StyleSheet {
static create(obj) {
var result = {};
for (var key in obj) {
StyleSheet.validateStyle(key, obj);
result[key] = StyleSheetRegistry.registerStyle(obj[key]);
}
return result;
}
// ...
}
As you see, no call to flatten on the initial commit, neither inside the create method, nor from the user using create.
In summary it seems this never changed and you could always access the styles using the dot operator.
As for whether to use it I don't think you have a choice. It clearly has some sort of validation code inside of it, it's also using type checking and the react team recommends using it. I don't see any other methods that do what it does. How could you use the class without create, just using some sort of init or constructor method? I don't see one on the class. There is no StyleSheet({...}); To get obj returned you need to call create.
Your editor could not give you IntelliSense if you strip away the validation behavior and make it a plain object. You won't know when you're making typos or referencing styles that don't exist, you won't have autocompletion. You'd need to create your own interfaces and use TypeScript. Thus you should use create because otherwise at a minimum you're breaking your IDE.

Calling a function of a component in a state array in react native

Kinda new to react/react-native.
I have a list component that contains an array of items in state
The list component sometimes query the server for information, and according to the information he gets from the server, he should update some things in the items state.
For testing purposes, I tried to do the something like the following:
componentWillMount() {
this.setState({posts: [<Item key={0} ... >, <Item key={1} ... >]}
}
...
testFunc() {
... // get data from server
this.state.posts[0].updateNewInfoFromServer(new_info);
}
But it didn't work, and it printed that the updateNewInfoFromServer function of my item component is undefined (it did the same when I tried to change it to any other function of my item component. It's pretty weird to me that I can't access the component's functions but I am able to access its props).
I also tried to add refs to the Items inside the posts array and then try to call this._myref.updateNewInfoFromServer inside the testFunc(), but I got exactly the same error..
What is the "react" way to solve this problem?
Thanks a lot!

Unknown custom element on downloaded template using Vue

I'll try to be short but clear.
I downloaded a template of Vuejs for admin (from here), but I am having troubles modifying it. I created one new component but I can't use it because is not being recognized. The console error says:
Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I don't know why is this happening because I am importing the component as every other one. Look the script code in the father component.
import LTable from 'src/components/UIComponents/Tables/Table.vue'
import ETable from 'src/components/UIComponents/Tables/EditableTable.vue' //THIS IS MY NEW COMPONENT
import Card from 'src/components/UIComponents/Cards/Card.vue'
const tableColumns = [//some data]
const tableData = [//some data]
export default {
components: {
LTable,
ETable, //THIS IS MY NEW COMPONENT
Card
},
data () {
return {
//some data
}
},
//some methods
}
Of course the name tag in my new component is 'edit-table'.
There is happening other strange issue: when I change the name value in the component imported as 'LTable' it seems not to matter because everything keeps working good.
Please, any help is appreciated it.