Passing array as props in React Native - reactjs

I have been reading a lot of threads and I couldn't find a solution to my problem.
I am passing some arguments to another React Native component in the following way:
<Footer buttonsActive={{ firstButton: 'true', secondButton: 'false' }} />
When I console log the parameter in Footer I get:
Object {
"buttonsActive": Object {
"firstButton": "true",
"secondButton": "false",
},
}
It looks fine, but when I try to console log the elements in the following way:
console.log(buttonsActive.firstButton);
I get an undefined error. What is the way to access these 2 values without iterating by using .map() and asking if (var == firstButton)....
Thanks

It may be the buttonsActive object that is not found is your context. It should be a prop inside your Footer.
Maybe try with console.log(this.props.buttonsActive.firstButton); inside the Footer.

I finally understood how it works, so one can send the parameters in this way:
<Footer firstButton secondButton={false} />
And one accesses them in the Footer component in this way:
const Footer = (buttonStatus) => {
const firstButtonColor = (buttonStatus.firstButton ? 'black' : 'grey');
const SecondButtonColor = (buttonStatus.secondButton ? 'black' : 'grey');
I hope it helps.

Related

Components not rendered when receiving arrays from parents

data.Example.map((item) => {
console.log(item.A)
return <ExampleBlock
a={item.A}
b={item.B}
/>
})
The data object in this code is imported from local json object. Here, console.log(item.A) just helps me to check if this is really an array.
postList.forEach(post => {
post.data.Example.map((item) => {
console.log(item.A)
return <ExampleBlock
a={item.A}
b={item.B}
/>
})
})
The postList here is imported from firestore. I exercise cautious here with console.log(item.A) and have verified that it's indeed an array like I drawn from local json file in the previous code set.
Both console.log shows the same thing.
Weird thing here is. The first set of code works just fine. It passed down the arrays as props and component is rendered perfect. The second set of code, the component wasn't rendered and it's just blank.
I've tried hard to think what's wrong and what's the difference. Would you guys please point me to the right direction. THanks.
It's due to the forEach which returns nothing. Replace it with a map as follows:
postList
.map((post) => post.data.Example)
.map((item) => {
console.log(item.A);
return <ExampleBlock a={item.A} b={item.B} />;
})

Change material of gltf-imported mesh programmatically - react three fiber

I'm currently working at a project with react-three-fiber. I've imported the model with useGLTF from #react-three/drei.
With
const { nodes, materials } = useGLTF('/model.glb');
I access the materials from the glb-file.
To access and manipulate the model I used gltfjsx to generate the model.
Now I need to change the material of a mesh programmatically. Because I have no direct access to the JSX of the model I do it with React.cloneElement and modify the props of the mesh.
So I tried something like this:
return React.cloneElement(mesh, {
material: overwriteMaterial ?
<meshStandardMaterial attach="material" color={0xa3005c} metalness={1} roughness={0.2} visible={true} /> :
materials['mat_7']
});
If overwriteMaterial is false it works. It shows the material it should. But if it's true then the mesh disappears.
I also thought of putting the <meshStandardMaterial /> in the children prop of the mesh. Something like so:
return React.cloneElement(mesh, {
material: overwriteMaterial ? undefined : materials['mat_7'],
children: overwriteMaterial ? <meshStandardMaterial attach="material" color={0xa3005c} metalness={1} roughness={0.2} visible={true} /> : undefined
});
With this I always get this error and I don't know why it appears:
TypeError: Cannot read properties of undefined (reading 'visible')
Could this approach somehow work or am I doing something completely wrong?
Every help is welcome. Thanks
Alright so I found the answer by myself after some more hours searching for a solution.
The material property doesn't accept a JSX-tag. So if you create an instance of the class MeshStandardMaterial you can pass it to the property and it works perfectly fine. Now it looks something like this:
return React.cloneElement(mesh, {
material: overwriteMaterial
? new MeshStandardMaterial({ color: 0x0ff000 })
: materials['mat_7']
})
Note: The class MeshStandardMaterial is exported from the three package.
i really don't think you have to clone any react element, that doesn't seem correct. you can clone or mutate materials just as you would in a plain three app. i have no idea why you even want to clone jsx.
const { scene } = useGLTF(url)
const clonedScene = useMemo(() => scene.clone(), [])
useLayoutEffect(() => {
clonedScene.traverse(o => {
if (o.type === 'Mesh') {
o.material = ...
}
})
}, [clonedScene]}
return <primitive object={clonedScene} />
you can skip the clonedScene thing completely as well, this is only if you plan to re-use the model in your scene multiple times.

React can not access variable from return

I am very new to React and I can not solve this issue for a very long time. The idea is the following, I get some user info from database and pass it into cookies. From react side I get this cookies as JSON object and I need to render menu for user depending on values in this object. Right now I pass this object that I get from cookies from parent Component and I try to access it from Settings component. The issue is that I can see access this object from test function, however when I try to access this data from return it gives me undefined error. The function that returns value from cookies is sync, I have no idea why that might happen, please help.....
Since this.state.shopSettings["new_orders"] is boolean, use ternary.
Don't copy props to the state inside constructor as the constructor is executed only once. So updates to the props won't be reflected in the component.
Like this
<button onClick={this.test}>
{props.shopSettings && (props.shopSettings["new_orders"] ? 'true button' : 'false button')}
</button>
It solves very easily with this code, now I can access any key from shopSettings inside return without any issues
class Index extends React.Component {
state = {
shopSettings: Cookies.getJSON('shopSettings')
}
render() {
const {shopSettings} = this.state
if (!shopSettings) {
return null
}
return (
<div>Hello</div>
)
}

Interpolation with <Link> of react-router

I'm working with react-router, and actually what I want is very simple, so I won't be too long, is just to get a string with a <Link> of react-router interpolated like:
const link = (
<Link to={"/terms"}>{"terms"}</Link>
);
const label = (
`something ${link}`
);
Actual result:
something [object Object]
Expected result:
something terms
Anybody knows how do I get the expected result?
I ran into the same issue and couldn't find a way to evaluate the Link object toString, within an interpolation; however, I found a workaround as (based on your setup) you can pass in multiple nodes in JSX as props. As an example, you could do something like:
label={
<div>
<span>something</span>
<Link to={'/terms'}>terms of use</Link>
<span> and other terms and such</span>
</div>
}
The link could then evaluate to the string/html output you are looking to render. Hope this helps !
You can take a look at: https://www.npmjs.com/package/jsx-to-html
Otherwise, you can use jsx-transform package which will give you information regarding the props you are passing.
const linkString = jsx.fromString(link, { factory: 'mercury.h' });
console.log(linkString); // 'Link({to: "/terms"}, ["terms"])'
Then you can use regex:
const linkPath = eval(linkString.match(/{(.*?)}/)[0]); // '/terms'
const label = `Whatever`;

How do properly use Onsen's Navigator in React?

I'm trying to implement a simple Onsen Navigator in React.
So far I'm receiving an error 'route is not defined' and I was looking through the examples & docs but I only saw the initialRoute prop was provided, how & where does the route prop generated or something? Cause it seems like its not specified.
Here is my the code of my component:
import React, {PropTypes} from 'react';
import ons from 'onsenui';
import * as Ons from 'react-onsenui';
class SignUp extends React.Component {
constructor(props) {
super(props);
this.state = {
index : 0
};
this.renderPage = this.renderPage.bind(this);
this.pushPage = this.pushPage.bind(this);
}
pushPage(navigator) {
navigator.pushPage({
title: `Another page ${this.state.index}`,
hasBackButton: true
});
this.setState({index: this.state.index++});
}
renderPage(route, navigator) {
return (
<Ons.Page key={route.title}>
<section style={{margin: '16px', textAlign: 'center'}}>
<Ons.Button onClick={this.pushPage}>
Push Page
</Ons.Button>
</section>
</Ons.Page>
);
}
render() {
return (
<Ons.Page key={route.title}>
<Ons.Navigator
renderPage={this.renderPage}
initialRoute={{
title: 'First page',
hasBackButton: false
}}
/>
</Ons.Page>
);
}
};
SignUp.propTypes = {
'data-pageName': PropTypes.string.isRequired
};
export default SignUp;
Is this the right syntax in ES6? Have I missed something?
When using Ons.Navigator in react the two required properties are:
initialRoute - it should be an object.
renderPage - method which receives 2 arguments - route and navigator. The route should be an object similar to the initialRoute one. You provide that object when you are calling pushPage and similar methods.
It seems that you already know these 2, but there still 2 other things which you need to be careful about. They are not directly onsen related, but come up a lot when using react in general.
Whenever you have a list of dom elements (for example an array of Ons.Page tags) each of those should have a unique key property.
Whenever you use a method you need to make sure you are binding it if you need some extra arguments.
It seems you also know these two. So the only thing left is to make sure you follow them.
Your syntax is correct - the only thing missing is the route variable in SignUp.render. Maybe you originally copied the renderPage method and that is how you have a leftover Ons.Page.
If you're not putting the SignUp component inside some other navigator, tabbar or splitter then you don't actually need the Ons.Page in its render method. Those are the only cases when they are needed. If you it happens to have one of those components as a parent then you can just specify the key.
PS: I think there should be a React Component Inspector (something like this) which you can install - then I think you may be able to see the place where the error occurs. I think if you knew on which line the problem was you would have been able to solve it. :)
For me, with the object I was passing to initialRoute(), it needed a props property, which itself was an object with a key property. See the before and after below.
Before fixing
render() {
return (
<Navigator
initialRoute={{component: DataEntryPage}}
renderPage={this.renderPage}
/>
);
}
}
This was causing the following console warning:
Warning: Each child in an array or iterator should have a unique "key" prop.
Check the render method of `Navigator`.
After fixing
render() {
return (
<Navigator
initialRoute={{component: DataEntryPage, props: {key: 'DataEntryPage'}}}
renderPage={this.renderPage}
/>
);
}
}
Notice that the difference I needed to make was the addition of , props: {key: 'DataEntryPage'}.
Feel free to check out this medium article for more information.

Resources