Adding custom prop to React-Native element? - react-native

I am trying to add custom prop to <Pressable/>. The solution I tried is:
type StyledButtonProps = {
correct: boolean,
clicked: boolean
}
const button = () => <Pressable></Pressable>
const StyledButton = React.cloneElement(button, {correct, clicked}) //Here this error comes at "button":
Argument of type '() => JSX.Element' is not assignable to parameter of type
'ReactElement<{ correct: [boolean, Dispatch<SetStateAction<boolean>>];
clicked: [boolean, Dispatch<SetStateAction<boolean>>]; }, string |
JSXElementConstructor<...>>'
And I will use it like this:
render(
<StyledButton onPress={...} correct={...} clicked={...} />
)
Here also comes warning: JSX element type 'StyledButton' doesnot have any construct or call signatures.
I couldn't find similar case, any help?

In React, to customize and add logic to a component, we create a component that renders the original and adds the styling or logic.
So just create a new component that gets every prop that Pressable gets, and the new props.
import { Pressable, PressableProps } from "react-native";
interface StyledButtonProps extends PressableProps {
correct: boolean;
clicked: boolean;
}
const StyledButton = ({ correct, clicked, ...other }: StyledButtonProps) => { // other - any other prop
// ...
return <Pressable {...other} />; // This way you pass all original Pressable props
}

Related

Why i am getting a warning about of string type if i am passing a string?

i want to pass a String to my child component like this, but previously i want to print it
this is my parent component
{{left.leftA}} // here show me 8
<CustomCard
:left="left.leftA"
export default {
name: 'Parent',
data() {},
setup() {
onMounted(async () => {
const answer = await getData(name)
left.value = answer.response //{leftA:'A', leftB:'B'...}
})
and in my child component i have this declaration
export default {
name: 'CustomCard',
props: {
left: {
type: String,
required: true,
},
i am getting this warning:
[Vue warn]: Invalid prop: type check failed for prop "left". Expected String with
value "undefined", got Undefined
Does it have something to do with how I am loading the data? is it ok to use onMounted?
This is happening because the initial value for value is null. So, on initial render it throws the warning, but upon another render it has the correct prop type (a string) and renders correctly.
You have 3 options. Allow '' as an option on the prop or don’t render the component until you have the correct data or make use of computed Property.
Option-1
{{left.leftA}} // here show me 8
<CustomCard
:left="left.leftA ? left.leftA : ''"
Option-2
{{left.leftA}} // here show me 8
<CustomCard v-if="loaded"
:left="left.leftA"
and in onMounted(}
onMounted(async () => {
const answer = await getData(name)
left.value = answer.response //{leftA:'A', leftB:'B'...}
// Set the loaded flag as true here. Also make sure its set as false inside the setup()
})
Option-3
{{left.leftA}} // here show me 8
<CustomCard
:left="sendVal"
In computed....
computed: {
sendVal() {
if(left && left.left1) return left.left1;
return '';
}
}

react native conditional rendering with section list and flatlist

I have two different components one is CategoryList which is a flatlist and regionlist is a section list. I would like to display the CategoryList first and when item clicked the regionlist will show however I m not sure why it is not working. (I use context to store the state)
{!isToggle ? (
<CategoryList></CategoryList>
) : (
<RegionList style={styles.regionListStyle}></RegionList>
)}
I also create a button to see if it is a problem about the context but it is not.
const ToggleContext = createContext(true);
export const useToggle = () => {
return useContext(ToggleContext);
};
export function ToggleProvideData({children}) {
const [isToggle, setToggle] = useState(true)
return <ToggleContext.Provider value={{isToggle,setToggle}}>
{children}
</ToggleContext.Provider>;
}
I just wonder conditional render is it not working for flatlist?
UPDATE: I tried create a state to store the useContext isToggle but it only appears for like 1 sec
I guess isToggle as a boolean variable, hence you can use the below code for rendering conditionally
{ (isToggle === true) &&
<CategoryList></CategoryList>
}
{ (isToggle === false) &&
<RegionList style={styles.regionListStyle}></RegionList>
}

How to toggle a boolean value using Context and Hooks?

I am using ReactContext and Hooks to show and hide a Modal on click of a button.
Following is my Context code
const setPrivacyPolicyModalVisibility = dispatch => {
return ({visible}) => {
visible
? dispatch({type: 'enablePrivacyPolicyModalVisibility'})
: dispatch({type: 'disablePrivacyPolicyModalVisibility'});
};
};
And the reducer code for the same is something as follows
case 'enablePrivacyPolicyModalVisibility':
return {...state, ...{enablePrivacyPolicy: true}};
case 'disablePrivacyPolicyModalVisibility':
return {...state, ...{enablePrivacyPolicy: false}};
Some setup code in my class
const {state, setPrivacyPolicyModalVisibility} = useContext(Context);
const [privacyVisibility, setPrivacyVisibility] = useState(false);
on click of button I am calling the following code
<TouchableOpacity
onPress={() => {
setPrivacyVisibility(true);
console.log(`${privacyVisibility}`);
setPrivacyPolicyModalVisibility({privacyVisibility});
}}.....
As you can see I am console logging the privacyVisibility value but it is always false which I fail to understand
Following is my code in the component to hide or show the Modal
{state.enablePrivacyPolicy ? (
<SettingsPrivacyModal visible={true} />
) : (
<SettingsPrivacyModal visible={false} />
)}
The Modal code is proper as I have tried setting default value to true just to check if modal is visible then it works, but on click of button press the state value does not change and I am not able to see the modal as the value is always false
The issue seems to be in the onPress callback:
onPress={() => {
const privacyVisibility_new = !privacyVisibility;
console.log( privacyVisibility_new );
setPrivacyVisibility( privacyVisibility_new );
setPrivacyPolicyModalVisibility( privacyVisibility:privacyVisibility_new );
}}
When the cycle reaches the callback privacyVisibility has the default which is false. I think you are assuming that once setPrivacyVisibility is called, the privacyVisibility variable will have the new value in that same cycle; but it won't have the updated value until the component renders again.
setPrivacyPolicyModalVisibility doesn't seem to be correct. I am not sure where is dispatch exactly, but assuming it is at the same level as the function you can simply use it inside.
const setPrivacyPolicyModalVisibility = visible => {
if ( visible ) {
dispatch({ type: "enablePrivacyPolicyModalVisibility" });
} else {
dispatch({ type: "disablePrivacyPolicyModalVisibility" });
}
};
You might want to simplify your reducer and send directly the visible value:
const setPrivacyPolicyModalVisibility = visible =>
dispatch({ type: "setPrivacyPolicyModalVisibility", payload: visible });
.
case 'setPrivacyPolicyModalVisibility':
return { ...state, is_privacyPolicy_visible: action.payload };
Actually the error was simple. I am using the visible parameter as props in setPrivacyPolicyModalVisibility but while setting I am passing prop of different name
Thanks to #Alvaro for pointing me in the right direction

mobx, render when a property value changes

I'm just getting started with Mobx in a react-native project and am having trouble understanding how to perform changes on a observed object.
Changing the object reference via the setWorkingObject action function in my store properly renders the UI, however if I just want to change a single property within this object, how do I cause a render?
My "store":
export default class MyStore {
constructor() {
extendObservable(this, {
workingObject: null
});
}
}
My "container":
class Container extends Component {
render() {
return (
<Provider store={new MyStore()}>
<App />
</Provider>
);
}
}
and my "component", which uses a simple custom input component (think of it like Checkbox) to perform changes to a property of my workingObject
class MyClass extends Component {
...
render() {
const {store} = this.props;
return
<View>
...
<RadioGroup
options={[
{ title: "One", value: 1 },
{ title: "Two", value: 2 }
]}
onPress={option => {
store.workingObject.numberProperty = option.value;
}}
selectedValue={store.workingObject.numberProperty}
/>
...
</View>
}
}
export default inject("store")(observer(MyClass));
I can't figure out why this doesn't work, in fact it looks very similar to the approach used in this example
Any other tips/critique on how I've implemented mobx welcome
The problem is that only existing properties are made observable at the time the workingObject is first assigned.
The solution is to declare future properties at the time of assignment, ie:
// some time prior to render
store.workingObject = { numberProperty:undefined };
First, you don't want to set initial value to null. Second, adding properties to observable object after it was created will not make added properties observable. You need to use extendObservable() instead of assigning new properties directly to observable object. Another solution is to use observable map instead.
in your store:
extendObservable(this, {
workingObject: {}
});
in your component:
extendObservable(store.workingObject, {numberProperty: option.value});
I recommend using Map in this case:
extendObservable(this, {workingObject: new Map()});
in your component:
store.workingObject.set(numberProperty, option.value);

Can I use multiple or nested elements in the Label of a Picker Item in React Native?

I'm using React Native with NativeBase and would like to make the labels of my Picker more complicated than just one plain string of text.
But is it even possible to pass elements as the label, say multiple child elements wrapped in a single top-level element?
Or do Pickers only support plain text as labels?
As requested by bennygenel, here's a version of what I've tried:
export default class ThingPicker extends React.Component {
render() {
const {
initialThing,
things,
onThingChanged,
} = this.props;
const orderedThings = things.sort();
return (
<Picker
selectedValue={initialThing}
onValueChange={onThingChanged}>
{buildThingItems(orderedThings)}
</Picker>
);
}
}
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = th === "BMD" ? (<Text key={th} label={"foo"} value={"bar"}}>Hello</Text>)
: (<Picker.Item key={th} label={th} value={th} />);
return it;
});
}
Yes! It is possible, it just might not look very "right" for React/JSX code. Just create the elements you need and assign them to the label field:
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = (<Picker.Item
key={th}
label={currency === "BMD" ? (<Text>Hello</Text>) : th}
value={th} />);
return it;
});
}