How to connect react-three-fiber to mobx - mobx

How to hook up react-three-fiber to mobx?
I have this component. How do I hook it up?
export default function Player(props) {
const mesh = useRef()
useFrame((a) => {
});
return (
<mesh>
<boxBufferGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={'orange'} />
</mesh>
)
}

Have you tried wrapping it with observer?
If that doesn't work, you can use a local state and set it through a reaction callback.

Related

Problem passing animatedPosition from BottomSheet to child to animate image

I cant seem to pass the onchange Y value from #gorhom/bottom-sheet. I can see the value when onchange in my App.js but I need to pass it another external component.
I am not sure if this involves using useDerivedValue or useEffect. I manage to pass the initial value from a state but even that is one behind.
I have an App.js that has the bottomSheet in it and another external .js file that loads images that are passed from the App.js, so everything is passing ok. Do I need to use useEffect to listen for changes?
As it stands I am using this in my App
const bottomSheetRef = useRef < BottomSheet > null;
// variables
const snapPoints = useMemo(() => [200, 538], []);
// callbacks
const handleSheetChanges = useCallback((index: number) => {
console.log("handleSheetChanges", index);
}, []);
const animatedPosition = useSharedValue(0);
const [currentPosition, setCurrentPosition] = React.useState(0);
useDerivedValue(() => {
console.log(
animatedPosition.value,
"here you will get value of every position"
);
}, [animatedPosition]);
useEffect(() => {
console.log(currentPosition);
}, [currentPosition]);
And how I am using it,
<BottomSheet
useRef={bottomSheetRef}
index={1}
snapPoints={snapPoints}
// onChange={handleSheetChanges}
animateOnMount={false}
animatedPosition={animatedPosition}
onChange={(index) => setCurrentPosition(index)}
>
This all works great but when I try to pass it, it does not update, I am using this code in my exertnal file,
export default function BottomSheetData(props) {
const {
show,
imga,
imgb,
imgc,
selectedItem,
imgWidthV,
imgHeightV,
animatedPosition,
} = props;
which gets all the relevant data just not the "live" changes?
I have tried everything but its now causing me a headache!!! I hope I have explained this issue properly and provided enough code. All I need it being pointed in the right direction or being told I am going around this in the totally wrong way.

How to create an rxjs Observable from TextInput (either onChange or onTextChange)

I want to create an observable from a change event that gets fired on a React Native TextInput component. TextInput comes with 2 change props that I'm aware of (onChangeText and onChange). From what I gather, you need to use onChange if you want access to the native event you need to use onChange.
I don't know much about the native event object. I am trying to create an rxjs observable using fromEvent.
First I created a ref in my functional component like this:
const sqftRef = useRef().current
Then I attached this ref to the TextInput component like this:
<TextInput
ref={sqftRef} // attach a ref
label='Sqft'
mode='flat'
textContentType='none'
autoCapitalize='none'
keyboardType='numeric'
autoCorrect={false}
value={String(formValues.sqft)}
dense
underlineColor={colors.colorOffWhite}
onChangeText={(text) => setText(text)}
onChange={e => {
// somehow create an observable from this event ???
}}
style={styles.inputStyles}
theme={inputTheme}
/>
I tried to create an Observable using fromEvent like this but it doesn't work. I get undefined is not an object (evaluating target.addEventListener):
fromEvent(sqftRef, 'onChange').subscribe(value => console.log(value))
I know my approach is all wrong. Hoping someone can point me in the correct direction.
I would emit events you need into a subject, then subscribe to the subject in other parts of your code.
Here's a simple React example that should get you started
function App() {
const textChange = new Subject<string>();
useEffect(() => {
// subscribe to
const subscription = textChange.asObservable().subscribe(console.log)
return () => subscription.unsubscribe()
}, [])
// Emit events with a subject
return <textarea onChange={(e) => {
textChange.next(e.target.value)
}}>
</textarea>
}
render(<App />, document.getElementById('root'));
Check out the example here: https://stackblitz.com/edit/react-ts-akoyfv
I think the problem is with assigning the current directly to the sqftRef. Try to define it without current, but use current when creating the Observable, like the following:
const sqftRef = useRef();
Then create the Observable within useEffect to make sure that the DOM is ready:
useEffect(() => {
fromEvent(sqftRef.current, 'onChange').subscribe((value) =>
console.log(value)
);
});
OK, I was able to figure it out with the help of Amer Yousuf and Alex Fallenstedt.
I did something similar to what Alex suggested, modifying his solution for React Native. One reason his solution wasn't working for me is that it is important to use the useRef hook to prevent the Observable from being re-created on each render. If the observable is recreated (on a re-render) and useEffect doesn't run again, then we won't have an active subscription to the newly (re-created) observable (useEffect never runs again). That's why my call to sqft$.next was originally only being called once (the first time until we re-render).
My solution looks like this:
let sqft$ = useRef(new BehaviorSubject(0)).current
useEffect(() => {
const sub = sqft$.subscribe({
next: (val) => {
// just testing stuff out here
updateForm('sqft', val)
updateForm('lot', val * 2)
}
})
// this is only relevant to my use case
if (activeReport) sqft$.next(activeReport.sqft)
return () => sub.unsubscribe()
}, [activeReport])
and of course I call this in onChangeText:
onChangeText={(text) => {
sqft$.next(text)
}}
So this is working right now. I still feel like there may be a better way using onChange(e => ...stuff). I will leave this question open for a little bit in case anyone can break down how to do this using nativeEvent or explain to me how I can access an event off the TextInput component.

react native and recoil multiple re-renders of RecoilRoot

I have these components without any recoil's hooks.
const C = () => {
console.log('---->C')
return <Text>C</Text>
}
const B = () => {
console.log('--->B')
return <>
<Text>B</Text>
<C/>
</>
}
const A = () => {
console.log('-->A')
return <>
<Text>A</Text>
<B/>
</>
}
const App = () => {
console.log('->App')
return (
<RecoilRoot>
<A />
</RecoilRoot>
);
};
when i run the app in the console show up the spected logs:
LOG ->App
LOG -->A
LOG --->B
LOG ---->C
now im gonna use recoil hooks to mutate and access the atom state
import { atom, useSetRecoilState, useRecoilState, useRecoilValue, RecoilRoot } from "recoil";
const atomTest = atom({
key: "abcatomTest",
default: "A"
})
const C = () => {
console.log('---->C')
const [value, set] = useRecoilState(atomTest)
return <>
<Text>C</Text>
</>
}
const B = () => {
console.log('--->B')
const set = useSetRecoilState(atomTest)
return <>
<Text>B</Text>
<C/>
</>
}
const A = () => {
console.log('-->A')
const value = useRecoilValue(atomTest)
return <>
<Text>A</Text>
<B/>
</>
}
const App = () => {
console.log('->App')
return (
<RecoilRoot>
<A />
</RecoilRoot>
);
};
i dont even using the values and functions returned from useRecoilValue, useSetRecoilState, useRecoilState, if i use it, it works properly, BUT in the very first render the logs are:
LOG ->App
LOG -->A
LOG -->A
LOG ->App
LOG --->B
LOG ---->C
LOG ---->C
LOG --->B
LOG -->A
LOG ->App
LOG -->A
LOG --->B
LOG ---->C
why is recoil forcing the re-render of multiple components including root, im not mutating the state at all, and in the App component there is not dependency to any state neither!
First of all: React executing a function does not mean that the component actually re-renders.
React has a commit and a rendering phase. During the commit phase React goes through changes and calls the child components, checking if there is anything new to render. During the rendering phase React checks if there are components that actually have to re-render. If the outputs, hook states and props are identical there will be no re-render, even though React previously called your function component. This is why you see all the logs. You are not checking for re-renders with that, but for function executions.
Your App component actually has dependencies to state, since it renders the RecoilRoot component. When that component changes, React will enter the commit phase again and go through all children, to see if there are changes.
Since every component uses a hook that references the atomTest atom, Recoil has to subscribe to that atom for that components. So Recoil as well as React have to look for changes through the tree.
If you check with the Profiler of the React Developer Tools you'll see that there are no actual re-renders, since your components didn't change any output.

what is the difference between passing an object with a variable and a lone variable to a react native component?

My lack of success in this problem may be due to a lack of proper terminology when Googling it but nonetheless I am completely stumped. I am passing an onPress function to a custom component in react native. When I pass it by itself as:
export const AddMorePlants = ( onPress ) => {
return (
<TouchableHighlight
onPress={onPress}>
.
.
.
}
I get a this2.props.onPress is not a function error but when I have the exact same code except with the onPress passed within curly braces:
export const AddMorePlants = ({ onPress }) => {
return (
<TouchableHighlight
onPress={onPress}>
.
.
.
}
It Works!
Why does the second one work and not the first?
Sorry for a kind of basic question I just have been really Googling and cant figure it out. Thanks in advance and I can provide any more info if needed.
A functional component in React only has one parameter. The props. You can read more about it here
So what your first attempt at passing the onPress function actually looks like is:
export const AddMorePlants = (props) => {
return (
<TouchableHighlight onPress={props}/>
);
}
When the TouchableOpacity tries to execute the method, it hits the is not a function error because props is an object.
When you do:
export const AddMorePlants = ({onPress}) => {
return (
<TouchableHighlight onPress={onPress}/>
);
}
what you are doing is something called destructuring assignment and it's equivalent of doing:
export const AddMorePlants = (props) => {
const {onPress} = props;
return (
<TouchableHighlight onPress={onPress}/>
);
}
By putting the brackets inside the parentheses you are just doing a shorthand version of this destructuring assignment that we have mentioned.
Here's another version that would also work:
export const AddMorePlants = (props) => {
return (
<TouchableHighlight onPress={props.onPress}/>
);
}
As you can see there are many ways to access an object's property.
The important part is to remember that the props object is the only parameter passed into a functional component.
I hope this helps you understand what's going on there.
In the first function you need to pass only one param i.e onPress to your component while in second you are destructuring assignment so you are doing something like onPress = this.props.onPress and passing an object of params.

React-Native - View config not found for name "Custom Tag"

I am using react-native-navigation v2 and every component needs to be registered into the navigation by calling registerComponent(). However, I found myself having 500 lines of code where I register every component of my app using the same registerComponent structure with the only difference of using different jsx tag for every component I register, like so:
import ItemsList from './src/components/ItemsList';
import { Navigation } from "react-native-navigation";
import { Provider } from "react-redux";
import reduxStore from "./src/store";
Navigation.registerComponent(
"app.ItemsList",
() => props => (
<Provider store={reduxStore}>
<ItemsList {...props} />
</Provider>
),
() => ItemsList
);
+++ 35 more components almost exactly just like this one
Now, in order to reduce that huge amount of identical code, I've decided to write an IIFE that maps through an array of objects(components) that look like:
[...,
{
name: "ItemsList",
component: ItemsList
},
...]
then calls registerComponent on every item and returns the JSX I need, like so:
(function componentsRegistration() {
return components.map(({ name, component }) => {
const Tag = name;
Navigation.registerComponent(
`app.${name}`,
() => props => (
<Provider store={reduxStore}>
<Tag {...props} />
</Provider>
),
() => component
);
});
})()
After this specific manipulation, my app doesn't render anymore. Instead it throws the "Invariant Violation: View config is not found for name ItemsList". I think I've made all of this respecting the React commandments (capital letter jsx tag, etc.), however can't get it to work. If anyone could, please help.
[SOLVED] I was getting an error because I was trying to pass a string with the component name instead of the component itself.
The right way to do it would be:
const Tag = component;
instead of:
const Tag = name;